一 什么是单例模式?
简单理解:在内存中某个实例对象只有一个,并由程序进程中的其他线程共享该实例。
在(一)多线程与并发之Volatile中,介绍了多线程是如何读写共享变量的。由此,我们可以知道,单例模式中的实例,在主存中只能创建并保存一份,其他线程需要使用该实例,需从主存中读取该实例,然后将实例副本保存在线程的工作内存中,供线程使用。
二 如何保证在主存中只存在一份实例?
(1)了解对象创建过程
第一步:分配内存空间
第二步:调用构造函数,初始化实例。
第三步:返回地址给引用
(2)禁止指令重排序
当构造函数在对象初始化的完成之前就完成了对象赋值,在内存中开辟一片存储区域后直接返回内存的引用,但是这个时候还没正真的初始化完对象,此时别的线程去判断instance != null,则会出现空指针异常。
(3)保证可见性
当A线程初始化对象,但还未刷新到主存,B线程正好也同时进行了相同的操作,则实际上创建了多个对象。
三 示例代码
基于以上考虑,可以引入volatile关键字来修改共享变量instance。
/**
* 单例模式
*/
public class Singleton {
//保证可见性和禁止指令重排序
private volatile static Singleton instance = null;
//私有构造函数
private Singleton(){}
public static Singleton getInstance(){
//第一重检查锁定
if (instance == null){
//同步锁定代码块
synchronized (Singleton.class){
if (instance == null){
//注意:非原子操作
instance = new Singleton();
}
}
}
return instance;
}
}