volatile通过lock指令触发mesi协议:写操作升级缓存行为m态并广播rfo使他核置i,读操作遇i态强制远程加载最新值,配合loadload/loadstore屏障防止重排序。

Java 中 volatile 通过触发 CPU 硬件级的 MESI 协议机制,让其他 CPU 核心“立刻知道”变量被修改了——它不靠 JVM 主动发消息,而是靠一条 lock 前缀指令激活硬件嗅探行为。
volatile 写操作触发 RFO 请求,强制升级缓存行为 M 状态
当线程写一个 volatile 变量时,JVM 会生成带 lock 前缀的汇编指令(如 lock xchg 或 lock addl $0, (%rsp))。这个指令会让当前 CPU 核心做两件事:
- 把该变量所在缓存行(Cache Line)状态从 S(共享)或 E(独享)提升为 M(已修改)
- 立即向总线广播 RFO(Read For Ownership)请求,意思是:“我要独占改这个地址,其他核请作废你们的副本”
其他核心靠总线嗅探(Bus Snooping)实时响应失效通知
每个 CPU 核心都持续监听总线上的内存事务。一旦收到 RFO 请求,它们会检查自己缓存中是否存在同一地址的缓存行:
- 如果状态是 S 或 E → 立即置为 I(Invalid)
- 如果状态是 M → 先将本地脏数据写回主内存(或同步给发起方),再置为 I
- 这个过程由硬件自动完成,无需软件干预,延迟通常在纳秒级
后续读操作因 I 状态被迫重新加载最新值
另一个线程读这个 volatile 变量时,CPU 会先查本地缓存行状态:
- 发现是 I → 不再尝试命中缓存,直接发起远程读(remote read)
- 目标可能是主内存,也可能是当前持有 M 状态的那个核心的缓存(取决于架构,如 Intel 的 cache-to-cache transfer)
- 加载完成后,缓存行状态变为 S(若其他核也有)或 E(若唯此核有),确保下一次读能快速命中
内存屏障配合 MESI,堵住单核内的乱序漏洞
MESI 解决跨核可见,但单核内仍可能因指令重排序破坏语义。所以 JVM 还会插入内存屏障:
- 写 volatile 后加 StoreLoad 屏障:强制刷空 Store Buffer,让 M 状态尽快生效并可被嗅探
- 读 volatile 前加 LoadLoad 和 LoadStore 屏障:防止该读被提前,也防止后续读写绕过这次加载
- 这些屏障在 x86 上常由 lock 指令或 mfence 实现,和 MESI 形成软硬协同
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











