volatile 通过 JVM 插入内存屏障(StoreStore+StoreLoad 写、LoadLoad+LoadStore 读)并协同 CPU 缓存一致性协议(如 MESI),强制刷新主内存、失效其他缓存行、重新加载最新值,从而保障可见性与有序性,但不保证原子性。

volatile 关键字在 Java 中不是靠“自动同步”起作用的,而是 JVM 依据 Java 内存模型(JMM)规则,在编译和运行时主动插入内存屏障指令,并协同 CPU 缓存协议(如 MESI)共同保障变量的可见性与有序性。
volatile 写操作如何让其他线程“看见”修改
当线程对 volatile 变量执行写操作(例如 flag = true),JVM 不仅更新当前线程的工作内存,还会:
- 在写操作之后立即插入 StoreStore + StoreLoad 内存屏障;
- StoreStore 确保该写之前的所有普通写(比如 counter = 42)已刷出到主内存;
- StoreLoad 是关键:强制将 volatile 写结果刷新至主内存,并触发缓存行失效(invalidate),使其他 CPU 缓存中对应变量的副本变为 Invalid 状态;
- 其他线程下次读该变量时,因本地缓存失效,必须从主内存或通过缓存一致性协议重新加载最新值。
volatile 读操作如何保证读到“最新值”
当线程读取 volatile 变量(例如 while (!flag)),JVM 不会直接复用工作内存旧值,而是:
- 在读操作之前插入 LoadLoad + LoadStore 内存屏障;
- LoadLoad 阻止后续读操作被重排到该 volatile 读之前,确保“先读 flag,再读其他变量”;
- LoadStore 保证该读操作一定在后续普通写之前完成;
- CPU 在执行该读时,会主动检查缓存一致性状态(如 MESI 协议),若缓存行处于 Invalid 或 Shared 状态,则从主内存拉取最新数据并更新本地缓存。
内存屏障如何与硬件协同生效
内存屏障不是抽象概念,它最终会翻译为特定 CPU 指令(如 x86 上的 mfence、lfence、sfence,或带 lock 前缀的空操作),其作用直连硬件:
立即学习“Java免费学习笔记(深入)”;
- 写屏障(如 StoreLoad)会触发写回(write-back)动作,并向其他核心广播缓存行失效请求;
- 读屏障(如 LoadLoad)会强制发起缓存同步检查,避免读到过期副本;
- MESI 协议配合这些信号,自动维护多核间缓存一致性:Modified 状态写回主存,Invalid 状态强制重载,从而让 volatile 的语义落地为真实硬件行为。
volatile 的能力边界要清楚
它解决的是单个变量的可见性与指令重排序问题,但不提供原子性保障:
- 不能替代 synchronized:i++ 这类复合操作仍需锁或 CAS;
- 不阻塞线程:无上下文切换开销,适合状态标志、中断信号等轻量场景;
- 不能修饰方法或局部变量:语法上仅限于成员变量和静态变量;
- 依赖 JMM 与硬件协作:脱离底层缓存协议和内存屏障机制,volatile 就失去意义。


















