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的重排序,来保证线程安全的延迟初始化。



京公网安备 11010502036488号