双重检测机制单例代码:
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) { 1
synchronized (Singleton.class) {
if (singleton == null) { 2
singleton = new Singleton(); 3
}
}
}
return singleton;
}
}
了解这个机制之前我们要知道一个定义指令重排:简单理解就是,虚拟机或者CPU会在不影响代码执行结果的情况下,改变代码的执行顺序来优化代码(单线程或正常同步情况下)
singleton = new Singleton()创建对象的过程不是原子性的分为三步:
①.分配对象的内存空间
②.初始化对象
③.将实例指向刚分配的内存地址
但在实际的情况因为指令重排 执行的顺序可能不是①》②》③,而是①》③》②
这就有可能会出现一个问题 : 线程A进入执行代码执行创建代码时执行了①》③时,线程B进入执行代码因为③已经执行了,singleton已经有了内存地址不是null了,所以if不成立直接返回singleton对象,但是由于还没有②初始化对象就会出现错误
为了解决这个问题要使用volatile
volatile主要有两个作用:①可见性 ②有序性
有序性顾名思义用来保证代码顺序执行,告诉虚拟机和CPU这段代码你必须按照顺序执行,不需要你优化。
这样就保证了创建对象必须按照①》②》③来执行,就不会再出现上述的问题了