单例模式 模式引入 问题描述 一个类只能有一个实例在生活中是很常见的,比如打印机程序,政府部门。当我们创建这些类的实例时,我们希望每次创建后得到的都是同一个实例。很直观地,我们知道需要在构造函数上下功夫,当我们需要创建一个新的实例时,如果已经有了该类的实例,就直接返回,而不是新建一个。 模式定义 此时,我们可以使用单例模式,它可以保证客户只能访问一个唯一的实例,而且还能保证没有其他实例可以被创建。 单例模式(Singleton)是保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
一个类只能有一个实例在生活中是很常见的,比如打印机程序,政府部门。当我们创建这些类的实例时,我们希望每次创建后得到的都是同一个实例。很直观地,我们知道需要在构造函数上下功夫,当我们需要创建一个新的实例时,如果已经有了该类的实例,就直接返回,而不是新建一个。
此时,我们可以使用单例模式,它可以保证客户只能访问一个唯一的实例,而且还能保证没有其他实例可以被创建。
单例模式(Singleton)是保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
对一些只需要一个全局实例的情况,推荐使用单例模式。
多线程时的单例模式
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。改善性能的双重锁定
Double-Check Locking。简单的静态初始化
两种方式对比:
双重锁定:
public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if(instance == null){ synchronized (Singleton.class) { if(instance == null){ instance = new Singleton(); } } } return instance; } }
静态初始化:
public class StaticSingleton { private static StaticSingleton instance = new StaticSingleton(); private StaticSingleton() { } public static StaticSingleton getInstance() { return instance; } }
Main 方法:
public class Main { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); if(s1 == s2) { System.out.println("两个对象是相同的实例。"); } // 多线程 Set<String> instanceSet = Collections.synchronizedSet(new HashSet<>()); for (int i = 0; i < 100; i++) { new Thread(() -> { instanceSet.add(Singleton.getInstance().toString()); }).start(); } for (String instance : instanceSet) { System.out.println(instance); } } }
执行结果:
两个对象是相同的实例。

单例模式优点包括:
单例模式缺点包括: