volatile写插入StoreStore+StoreLoad屏障,确保前面普通写不重排到其后、其后读写不提前;读插入LoadLoad+LoadStore屏障,禁止后续读写重排到其前。

Java 中 volatile 变量的读写能防止前后指令重排,靠的是 JVM 在编译和运行时自动插入特定组合的内存屏障(Memory Barrier),而非开发者手动控制。这些屏障在硬件、JIT 和编译器三个层级协同生效,只约束与该 volatile 变量存在 happens-before 关系的操作,不干预无关指令。
volatile 写操作:插入 StoreStore + StoreLoad 屏障
当执行 flag = true; 这类 volatile 写时,JVM 保证:
-
StoreStore 屏障:它前面的所有普通写(如
num = 2;、obj.field = 1;)不会被重排到该 volatile 写之后; -
StoreLoad 屏障:它后面的所有读或写操作(如
r = data;或count++;)不会被重排到该 volatile 写之前。
这使得 volatile 写成为一条“写完成分界线”。例如:
num = 2;ready = true; // volatile 写 → 此处插入 StoreStore + StoreLoad
编译器和 CPU 都不会把 num = 2 挪到 ready = true 后面,也不会让后续语句提前执行——从而确保“初始化完成后再发布状态”。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
volatile 读操作:插入 LoadLoad + LoadStore 屏障
当执行 if (ready) 这类 volatile 读时,JVM 保证:
-
LoadLoad 屏障:它前面的所有普通读(如
r1 = a;)必须先于该 volatile 读完成(即不能延迟); -
LoadStore 屏障:它后面的所有写操作(如
result = r1 * 2;)不能被重排到该 volatile 读之前。
这使得 volatile 读成为一条“读可见分界线”。例如:
if (ready) { // volatile 读 → 此处插入 LoadLoad + LoadStorer = num + num; // 这行不会被提前到 if 判断前
}
一旦读到 ready == true,就能安全使用此前由写端按序发布的所有数据(如 num 的最新值)。
屏障效果跨三层落地,但作用范围有限
内存屏障不是抽象概念,而是贯穿整个执行链路的具体约束:
- 编译器层:javac 和 JIT 主动禁用字段冗余消除、逃逸分析等可能破坏顺序的优化;
-
JIT 层:生成汇编时,x86 上常用
lock addl $0,0(%rsp)或mfence,ARM 上用dmb ish; - CPU 硬件层:屏障指令干预流水线,并触发 MESI 等缓存一致性协议,强制刷新或失效缓存行。
但它只管“相关”,不管“全局”:
- 不约束两个非 volatile 变量之间的重排;
- 不提供原子性(
count++仍需AtomicInteger); - 不禁止连续两次 volatile 写之间的重排(如
v1 = true; v2 = true;之间仍可能被重排)。

















