为什么双重校验锁(DCL) 还需要 volatile (内存屏障)来保证有序性?

文章讨论了Java中一条语句可能因编译器优化而被解析成多步执行,这可能导致原子性问题。在单例模式的实现中,如果不使用volatile修饰instance变量,可能会出现线程A创建对象但未完成时,线程B误认为对象已初始化并返回未完整对象的问题。双重校验锁(DCL)的目的在于确保线程安全,但不加volatile可能会导致线程可见性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前置知识点,Java 中一条语句可能被解析成多条指令分别执行(不一定保证原子性)

如下语句:

User user = new User();

会被解析成多步操作执行

  1. 在堆内存中为新的 User 对象分配空间。
  2. 在栈内存中为变量 user 分配空间。
  3. 调用 User 类的构造函数来初始化这个新对象。
  4. 将新创建的 User 对象在堆内存中的地址赋值给栈内存中的变量 user

正常情况下,应该会按照顺序执行,但是由于编译器有优化执行顺序的功能(提升cpu执行的效率),所以不一定是按照此顺序执行;
但是优化一定会保证 单线程情况下,执行结果的正确性.

比如优化的结果可能是,1243 ,在单线程情况下不会出现问题.

如果双重校验锁(DCL) 不加 volatile (内存屏障)会出现什么问题

public class SingleInstance {

    private static SingleInstance instance;
//    private static volatile SingleInstance instance;

    private SingleInstance() {
    }

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

可能出现的情况:

线程A: 执行顺序为 1243,但是执行到了第4步就发生了线程切换,此时对象还没有初始化

线程B:切换到B线程时,才到 instance == null 这一步,由于 线程A 已经执行了变量赋值操作,所以 instance == null 为 false,便 retrun 了一个 未初始化的 instance;

代码仓库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值