双重校验锁 为啥要用volatile修饰

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的代码可以分解为三个部分

  1. 分配对象的内存空间
  2. 初始化对象
  3. 设置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的重排序,来保证线程安全的延迟初始化。

猜你喜欢

转载自blog.csdn.net/OrangeRawNorthland/article/details/83788412
今日推荐