一、volatile+synchronized实现方案
package com.example.myapplication;
public class TestSingleton {
private static volatile TestSingleton testSingleton;
public static TestSingleton getInstance(){
if(testSingleton == null){
synchronized (TestSingleton.class){
if(testSingleton == null){
testSingleton = new TestSingleton();
}
}
}
return testSingleton;
}
}
原因:volatile防止指令重排序
testSingleton = new TestSingleton();
这一行代码创建了一个对象,创建过程可以分解为如下3行伪代码。
memory = allocate(); //1.分配对象的内存空间
ctorInstance(memory); //2.初始化对象
testSingleton= memory; //3.设置testSingleton指向刚分配的内存地址
其中第2和3之间,可能会被重排序。因为java中允许那些在单线程内,不会改变单线程程序执行结果的重排序。上面伪代码2和3之间虽然被重排序,单不会影响最终结果。2、3重排序之后的执行时序如下。
memory = allocate(); //1.分配对象的内存空间
testSingleton= memory; //3.设置testSingleton指向刚分配的内存地址
//注:此时对象还没有被初始化!
ctorInstance(memory); //2.初始化对象
因此,如果发生重排序,另一个并发执行的线程就有可能判断testSingleton不为null。然后线程接下来将访问这个对象,但此时对象还没有被初始化!所以我们要使用volatile关键字防止指令重排序。