public class Singleton {
private static Singleton singleton;
public static Singleton getInstance(){
if (singleton == null){
synchronized (Singleton.class){
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
原因
在代码执行到singleton = new Singleton();时,这一步会分解成3个步骤:
1.分配内存空间
2.创建对象
3.singleton引用指向内存空间
由于2,3操作之间没有依赖关系,JAVA编译器可能会对其进行指令重排,此时会出现3->2情况,当一个线程进行3时,而2未初始化完成,则会出现异常。
解决办法
1.不允许2和3进行重排序
对singleton增加votatile关键字,保证只有一个线程获取singleton。
2.允许2和3重排序,但不允许其它线程"看到"这个重排序。
原理:JVM在类的初始化阶段(Class加载后且被线程使用前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化,基于这种特性,实现另一种线程安全的延迟初始化方案:
public class InstanceFactory {
public static Instance getInstance(){
return InstanceHolder.instance;
}
private static class InstanceHolder{
public static Instance instance = new Instance();
}
}
如果两个线程并发执行getInstance()方法:
执行的实质是:允许线程A中的2和3重排序,但不允许线程B"看到"这个重排序