public class Singletone{
private static Instance instance;
public Instance getInstance(){
if(instance == null){
synchronized(Singletone.class){
if(instance == null){
instance = new Instance();
}
}
}
return instance;
}
}
问题:
instance = new Instance();
是由三个步骤组成的:
但是第2,3步可能发生指令重排列,导致先将引用指向一个未实例化对象的内存地址,然后再进行实例化对象。
若此时第二个线程进行第一个非空判断时,则为false,会直接返回还没有实例化对象的内存地址,从而可能产生异常。
解决:
volatile
禁止指令重排列public class Singletone{
private volatile static Instance instance;
public Instance getInstance(){
if(instance == null){
synchronized(Singletone.class){
if(instance == null){
instance = new Instance();
}
}
}
return instance;
}
}
在成员变量中加入volatile
变量,禁止使用new创建对象时的指令重排列。
public class Singletone{
private static class InstanceHolder{
public static Instance instance = new Instance();
}
public static Instance getInstance(){
return InstanceHolder.instance;
}
}
JVM在类初始化阶段进行类的初始化。在初始化期间,JVM会获取一个锁,从而同步多个线程对同一个类的初始化。
第一个获得锁的线程会完成实例对象的创建,其他线程会直接获取创建的实例对象。
参考:
原文:https://www.cnblogs.com/truestoriesavici01/p/13287258.html