欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java中双检锁里volatile的作用

程序员文章站 2022-07-14 09:09:57
...

懒汉式

public class Singleton {
    private static Singleton instance;
    private Singleton(){}

    public static Singleton getInstance(){
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

饿汉式(线程安全)

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

双检锁(线程安全)

public class Singleton {
    private volatile static Singleton instance;
    private Singleton(){}

    public static Singleton getInstance(){
        if (instance == null){ // 第一次检查
            synchronized (Singleton.class){
                if (instance == null) // 第二次检查
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

Java中双检锁里volatile的作用

双检锁中在第二次检查后创建对象的代码
instance = new Singleton();
可以分解为如下的3行伪代码

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

上面3行伪代码中的2和3之间,可能会被重排序。2和3之间重排序之后的执行时序如下:

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

这样在多线程下可能会发生问题,即当线程A执行完里面的1、3过程时,线程B在判断出instance不为空就会直接访问instance引用的对象。此时,线程B将会访问一个还未初始化的对象。

当声明对象的引用为volatile后,3行伪代码中的2和3之间的重排序,在多线程环境下将会被禁止,保证了线程安全的延迟初始化。