volatile通过插入内存屏障(如StoreStore、StoreLoad、LoadLoad、LoadStore)约束指令重排序,建立happens-before关系,保障可见性与有序性,但不保证原子性。

Java 中 volatile 并不直接“禁止”编译器或 CPU 的指令重排序,而是通过在关键位置插入 内存屏障(Memory Barrier),向 JVM 和硬件发出明确的顺序约束,让某些指令不能跨越屏障移动,从而在多线程场景下保障逻辑上的执行顺序。
靠内存屏障限制指令移动范围
JVM 在编译 volatile 变量的读写时,自动插入四类屏障:
- 写操作前插入 StoreStore 屏障:确保该写之前的所有普通写操作,不会被重排到它之后
- 写操作后插入 StoreLoad 屏障:阻止后续的读操作被提前到该写之前执行
- 读操作前插入 LoadLoad 屏障:保证该读之前的所有普通读操作,不会被重排到它之后
- 读操作后插入 LoadStore 屏障:防止后续的写操作被提前到该读之前
依托 happens-before 规则建立跨线程顺序
volatile 是 Java 内存模型(JMM)中定义的核心 happens-before 关系之一:
- 对一个 volatile 变量的写操作 happens-before 后续对该变量的读操作
- 这个“后续”不要求代码紧邻,只要读发生在写之后(逻辑上或实际执行中)就成立
- 结合程序次序规则和传递性,可推导出更长的可见性链。例如:
x = 1; flag = true;(flag 是 volatile),那么x = 1就一定在flag = true之前对其他线程可见
底层靠 lock 指令触发硬件同步
在 x86 平台,volatile 写通常编译为带 lock 前缀的机器指令(如 lock addl $0x0,(%rsp)),它会强制:
立即学习“Java免费学习笔记(深入)”;
- 将当前 CPU 缓存行数据立即写回主内存
- 使其他 CPU 中对应缓存行失效
- 形成天然的执行顺序锚点,阻止处理器乱序执行跨越该指令
注意它的作用边界
volatile 的约束有明确范围:
- 只作用于 volatile 读/写自身及与其有数据依赖的前后普通读写
- 不保证全局所有指令的绝对顺序,也不影响无关变量之间的重排
- 不提供原子性——像
count++这样的复合操作仍需synchronized或AtomicInteger


















