volatile 不直接触发硬件动作,而是通过 JVM 插入 lock 指令和内存屏障,驱动 MESI 协议完成缓存行状态迁移、RFO 广播、无效化及强制重加载,实现线程间变量的可见性。

Java 中 volatile 关键字本身不直接“触发”硬件动作,而是通过 JVM 生成特定指令,间接驱动 CPU 执行 MESI 协议下的标准缓存状态迁移和总线交互。
volatile 写操作激活 MESI 状态转换
当线程写一个 volatile 变量时,JVM 会插入带 lock 前缀的汇编指令(如 lock xadd 或 lock addl $0, (%rsp)),这会强制:
- 将该变量所在缓存行(Cache Line)的状态从 E(独享)或 S(共享)升级为 M(已修改)
- 发起 RFO(Read For Ownership)请求,通过总线广播通知其他核心:我要独占写这个地址
- 其他核收到 RFO 后,若本地有同地址缓存行,一律将其置为 I(无效)状态
volatile 读操作强制缓存重加载
当线程读一个 volatile 变量时,CPU 检查本地缓存行状态:
- 若为 I(无效),必须触发远程读(remote read)——从主内存或拥有 M 状态的核缓存中拉取最新值
- 该过程绕过 Store Buffer,避免因写缓冲延迟导致的可见性滞后
- JVM 同时插入
LoadLoad和LoadStore内存屏障,防止后续读写被重排到该读之前
底层依赖总线嗅探与状态协同
MESI 协议的运行离不开硬件级总线嗅探(Bus Snooping)机制:
立即学习“Java免费学习笔记(深入)”;
- 每个 CPU 核持续监听总线上的内存事务,实时感知 RFO、Write 等信号
- 状态迁移不是孤立发生,而是多核间响应式协作:一核进 M,其余核同步进 I
- 所谓“立即可见”,本质是 I 状态触发的强制重加载,而非数据被立刻刷入物理 RAM
不等于强制写回主内存
MESI 协议本身不要求 M 状态缓存行立刻回写主存:
- M 状态可长期驻留缓存,直到被替换、被其他核请求(如 cache miss 触发 shared 请求),才需写回
-
lock指令隐含StoreLoad屏障,会清空本核 Store Buffer,使 M 行更快进入回写队列 - “近似立即刷盘”的效果是协议+屏障+缓存策略共同作用的结果,不是 volatile 的直接承诺


















