JVM指令重排导致Singleton双重锁定出错
2017-03-16 15:56
253 查看
指令重排导致单例模式失效
我们都知道一个经典的懒加载方式的单例模式:public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
看似简单的一段赋值语句:instance = new Singleton();,其实JVM内部已经转换为多条指令:
memory = allocate(); //1:分配对象的内存空间
ctorInstance(memory); //2:初始化对象
instance = memory; //3:设置instance指向刚分配的内存地址
但是经过重排序后如下:
memory = allocate(); //1:分配对象的内存空间
instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化
ctorInstance(memory); //2:初始化对象
可以看到指令重排之后,instance指向分配好的内存放在了前面,而这段内存的初始化被排在了后面,在线程A初始化完成这段内存之前,线程B虽然进不去同步代码块,但是在同步代码块之前的判断就会发现instance不为空,此时线程B获得instance对象进行使用就可能发生错误。
修改:
public class Singleton { private static volatile Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if(instance == null) { synchronzied(Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } }
相关文章推荐
- 深入理解JVM 系列JVM运行机制 JVM内存模(volatile,指令重排)
- JVM 中的指令重排
- Singleton(单例)模式和Double-Checked Locking(双重检查锁定)模式
- JVM 指令重排
- 单例(Singleton) 双重锁定(Double-Check Locking)
- 深入理解JVM 系列JVM运行机制 JVM内存模(volatile,指令重排)
- (八 附)java并发编程--JVM之指令重排分析
- JVM之指令重排分析
- 双重检验锁定单例模式的优化写法(非volatile,全版本jvm通用)
- JVM之指令重排分析
- jvm(二)指令重排 & 内存屏障 & 可见性 & volatile & happen before
- JVM之指令重排分析
- Design Pattern_Singleton(单件模式)和Double-Checked Locking(双重检查锁定)
- JVM内存模型、指令重排、内存屏障概念解析
- JVM内存模型、指令重排、内存屏障概念解析
- JVM 编译之指令重排
- Singleton - 单例模式和Double-Checked Locking - 双重检查锁定模式
- JVM之指令重排分析
- inline函数使用容易导致出错的问题
- 太郁闷了,新建项目的时候不小心改了一个地方,导致已用到java类或者servlet 就出错!