youyichannel

志于道,据于德,依于仁,游于艺!

0%

Volatile全解读-05

未使用volatile下的双重检查锁

public class DoubleCheckedLocking { // 1
private static Instance instance; // 2

public static Instance getInstance() { // 3
if(instance == null) { // 4 第一次检查
synchronized(DoubleCheckedLocking.class) { // 5 加锁
if(instance == null) { // 6 第二次加锁
instance = new Instance(); // 7 问题根源
}
} // 8
} // 9
return instance; // 10
} // 11
}

双重检查锁锁定了instance = new Instance();创建了一个对象,这一行代码可以分解为下面三行伪代码:

memory = allocate(); // 1. 分配对象的内存空间
ctorInstance(memory); // 2. 初始化对象
instance = memory; // 3. 设置instance指向刚分配的内存地址

上述的伪代码中,2和3之间,可能会被重排序,在一些JIT编译器上,这种重排序是真实发生的。

2和3之间重排序之后的执行时序如下:

memory = allocate(); // 1. 分配对象的内存空间
instance = memory; // 3. 设置instance指向刚分配的内存地址 => ⚠️注意:此时对象还没有初始化
ctorInstance(memory); // 2. 初始化对象

重排序之后,就有可能拿到没有经历初始化的对象,这是非常危险的。

视频地址 强推 河北王校长