volatile在JMM中核心是插入内存屏障:写操作插入StoreStore和StoreLoad屏障,读操作插入LoadLoad和LoadStore屏障,以此约束重排序并保障可见性边界,而非简单“直刷主存”。

volatile 在 Java 内存模型(JMM)中起作用,核心不是“直接操作主内存”,而是通过编译器和 JVM 在字节码层面插入特定的内存屏障(Memory Barrier),来约束指令重排序、控制读写可见性边界。它不改变硬件缓存行为本身,而是告诉 CPU 和编译器:“这里必须按这个顺序执行,且某些操作必须对其他线程可见”。
volatile 写操作触发两类屏障
当对一个 volatile 变量执行写操作(如 y = true)时,JVM 保证在该写指令前后插入:
- StoreStore 屏障:确保该 volatile 写之前的所有普通写操作(如 x = 42)已刷新到主内存,再执行 volatile 写;
- StoreLoad 屏障:这是最严格的屏障,强制所有之前的写操作(包括 volatile 写)全部完成并可见后,才允许后续的任意读操作(包括 volatile 读或普通读)开始执行。
volatile 读操作触发两类屏障
当读取一个 volatile 变量(如 if (y))时,JVM 在该读指令前后插入:
掌握 ES6+ 特性,包括 async/await、解构、扩展运算符、箭头函数、Promise、模块、迭代器、生成器以及函数式编程模式,编写简洁高效的 Java
- LoadLoad 屏障:确保该 volatile 读之前的所有读操作已完成,再执行该 volatile 读;
- LoadStore 屏障:确保该 volatile 读完成后,后续的写操作(无论是否 volatile)才可开始执行。
屏障如何协同解决实际问题
以双重检查锁定(DCL)单例为例:
立即学习“Java免费学习笔记(深入)”;
- 对象构造可能被 JIT 重排为:分配内存 → 设置引用 → 初始化字段;
- 若没有 volatile,另一个线程可能看到非 null 的引用,但字段尚未初始化;
- 加上 volatile 后,StoreLoad 屏障阻止了“设置引用”与“初始化字段”的重排,同时 LoadLoad + LoadStore 确保读取引用后能正确看到已初始化的字段值。
注意:屏障是语义保障,不是硬件指令直译
不同 CPU 架构实现内存屏障的方式不同(如 x86 的 mfence、ARM 的 dmb ish),JVM 会根据平台选择等效指令。你不需要手写这些指令,但需理解:volatile 的效果不是靠“每次都刷主存”这种粗粒度操作,而是靠精准插入的屏障,在关键路径上建立同步语义边界。

















