单例模式

59 阅读1分钟

线程安全的懒汉式

class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance==null){
            synchronized (Singleton.class){
                if (instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

第一次检查instance==null是为了防止实例已经被创建好时,重复去创建,同时防止不必要的加锁操作。

增加第2次检查instance==null:当一个线程正在执行new Singleton()创建实例,其他线程执行到第一个if (instance==null)之后,而在synchronized之前,即其他线程已经闯过了第一次检查,接着执行new Singleton()的线程创建好了实例,并释放了锁,那么其他线程便可以进入synchronized代码块中去再次创建实例,第2次检查instance==null就是为了防止这种情况下重复创建实例。

volatile是为了使instance=new Singleton(),避免指令重排。

  1. 给 instance 分配内存 new
  2. 调用 Singleton 的构造函数来初始化成员变量 Singleton()
  3. 将instance引用指向分配的内存空间 = (执行完这步 instance 就为非 null 了)

如果按1-3-2的顺序执行,执行完3时,其他线程就能拿到实例了,但此时2还没有执行,创建的实例是有问题的。

线程安全的饿汉式

public class Singleton{
    //类加载时就初始化
    private static final Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

单例会在加载类后一开始就被初始化,即使客户端没有调用 getInstance()方法。

Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。