Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


单例双重校验为什么还要加 volatile

Java 面试 大约 956 字

单例代码

双重校验 + volatile

public class Singleton {

    //防止在new对象时指令重排序
    private static volatile Singleton instance;

    private Singleton() {
    }

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

原因

Java层面实例化对象时instance = new Singleton();底层C代码实际分为3个步骤:(字节码层面也可以看到分为了三步)

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

如果不加volatile关键字,可能发生指令重排序(虽然概率很低),导致初始化对象这一步在指向内存地址之后。若此时其他线程调用getInstance()方法,实例已经不为null了,则第一个 if 就判断了不为 null 直接返回,但此时仅仅是指向了一个分配好的内存地址,并没有真正完成实例化,导致空指针。

memory = alloct(); // 1. 分配对象的内存空间
instace = memory; // 3. 设置 instace 指向刚分配的内存地址
                  // 这一步此对象还没有被初始化,若其他线程来调用 getInstance(),就有问题了
ctorinstance(memory); // 2. 初始化对象
阅读 394 · 发布于 2022-05-18

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批