volatile 保证可见性的底层原理(核心)
volatile的可见性并非 “跳过缓存直接读写总线 / 主存”,而是通过两个机制强制缓存同步:
1. 缓存一致性协议(MESI)
CPU 层面的硬件协议(Intel 架构为主),解决多核心缓存同步问题,核心逻辑:
- 当某个 CPU 核心修改了
volatile变量的缓存行(Cache Line),会将该缓存行标记为「已修改(Modified)」; - 同时通过「总线嗅探(Bus Snooping)」机制,通知其他核心:该变量的缓存行已失效(Invalid);
- 其他核心再读取该
volatile变量时,发现自己的缓存行失效,会主动丢弃私有缓存的旧值,从主存重新加载最新值。
2. 内存屏障(Memory Barrier)
JVM 层面为volatile变量的读写添加的 “屏障指令”,禁止 CPU 重排序并强制缓存同步:
- 写屏障(Store Barrier):对
volatile变量写操作后,插入写屏障,强制将私有缓存中的修改刷回主存,且保证写操作之前的指令不会被重排序到屏障之后; - 读屏障(Load Barrier):对
volatile变量读操作前,插入读屏障,强制清空私有缓存的旧值,从主存重新加载最新值,且保证读操作之后的指令不会被重排序到屏障之前。
volatile 的正确执行流程
以线程 A 修改volatile变量、线程 B 读取该变量为例:
- 线程 A 修改
volatile变量:- 先修改自己私有缓存中的副本;
- 写屏障触发:将修改后的缓存行刷回主存,并通过 MESI 标记其他核心的该缓存行为 “失效”;
- 线程 B 读取该
volatile变量:- 读屏障触发:检查私有缓存,发现缓存行已失效;
- 主动从主存加载最新值到自己的私有缓存;
- 线程 B 读取私有缓存中的最新值(而非直接读总线 / 主存)