public class Single {
private static volatile Single single;
public static Single getSingle(){
if (single==null){
synchronized (Single.class){
if (single==null){
single=new Single();
}
}
}
return null;
}
}
因为如果不用volatile修饰的话,在 single=new Single();会发生指令重排序,
Single的代码可以分解为三个部分
- 分配对象的内存空间
- 初始化对象
- 设置single指向内存空间
在JIT里,可能会将2与3进行重排序,在单线程里这里并不会发生什么问题,但是在多线程情况下,会出现下面的问题
时间 | 线程A | 线程B |
t1 | A1:分配对象的内存空间 | |
t2 | A3:设置single指向内存空间 | |
t3 | B1:判断single是否为空 | |
t4 | B2:由于single不为null,线程B将访问single引用的对象 | |
t5 | A2:初始化该对象 | |
t6 | A4:访问single引用的对象 |
A2与A3重排序后,会让线程B在B1处判断出single不为null,线程B接下来将访问的single引用的对象是一个未初始化的对象。
所以用volatile修饰 single来就是禁止2与3的重排序,来保证线程安全的延迟初始化。