如何通过双重检查锁定(DCL)的原子性来理解为何在禁止指令重排中volatile关键字至关重要?
- 内容介绍
- 相关推荐
本文共计1038个文字,预计阅读时间需要5分钟。
很多人误以为 `volatile` 在 DCL (Double-Check Locking) 中是用来保证原子性的,这是典型误解。DCL 的原子性依赖于 `synchronized` 块——它包括了对象的创建和赋值过程,确保同一时刻只有一个线程能执行这部分代码。而 `volatile` 根本不提供复合操作的原子性保证,例如 `volatile++` 依然是不安全的。
它的真正作用在别处:防止 JVM 或 CPU 将对象初始化的三步指令(分配内存 → 调用构造函数 → 赋值给静态引用)乱序执行。没有 volatile,第 3 步(instance = memory)可能被提前到第 2 步(ctorInstance(memory))之前,导致其他线程看到一个“已赋值但未初始化”的对象引用。
为什么 synchronized 不能完全替代 volatile?
synchronized 确实能保证临界区内的有序性,但它只约束块内代码;一旦线程 A 退出同步块,对 instance 的写入如果不加 volatile,就无法保证对线程 B 的“立即可见”+“顺序可见”。
本文共计1038个文字,预计阅读时间需要5分钟。
很多人误以为 `volatile` 在 DCL (Double-Check Locking) 中是用来保证原子性的,这是典型误解。DCL 的原子性依赖于 `synchronized` 块——它包括了对象的创建和赋值过程,确保同一时刻只有一个线程能执行这部分代码。而 `volatile` 根本不提供复合操作的原子性保证,例如 `volatile++` 依然是不安全的。
它的真正作用在别处:防止 JVM 或 CPU 将对象初始化的三步指令(分配内存 → 调用构造函数 → 赋值给静态引用)乱序执行。没有 volatile,第 3 步(instance = memory)可能被提前到第 2 步(ctorInstance(memory))之前,导致其他线程看到一个“已赋值但未初始化”的对象引用。
为什么 synchronized 不能完全替代 volatile?
synchronized 确实能保证临界区内的有序性,但它只约束块内代码;一旦线程 A 退出同步块,对 instance 的写入如果不加 volatile,就无法保证对线程 B 的“立即可见”+“顺序可见”。

