双重锁检测单例模式中volatile的理解
程序员文章站
2022-03-11 18:31:46
...
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
这种情况下,会有风险,是指令重排序导致的问题
instance = new Singleton(),正常的指令顺序是:
- memory = allocate(); //1:分配对象的内存空间
- ctorInstance(memory); //2:初始化对象
- instance = memory; //3:设置instance指向刚分配的内存地址
但是经过重排序后如下:
- memory = allocate(); //1:分配对象的内存空间
- instance = memory; //3:设置instance指向刚分配的内存地址
- //注意,此时对象还没有被初始化!
- ctorInstance(memory); //2:初始化对象
将第2步和第3步调换顺序,在单线程情况下不会影响程序执行的结果,但是在多线程情况下就不一样了。线程A执行了instance = memory(这对另一个线程B来说是可见的),此时线程B执行外层 if (instance == null),发现instance不为空,随即返回,但是得到的却是未被完全初始化的实例,有人说synchronized不是可以禁止重排序吗?这只是假象,是因为不加锁后是单线程,这种情况下无论重排序或者不重排序,结果都是一样的,synchronized并不是禁止了重排序,而是即使重排序,也不影响其结果!