volatile字段未被改写时,循环读并非每次从主内存读取
核心结论:当volatile字段始终未被任何线程改写时,循环读取该volatile字段不会每次从主内存加载,而是优先从当前核心的L1/L2私有缓存(或L3共享缓存)中读取——volatile读的核心规则是“读前保证缓存行有效,而非强制绕开缓存、直接访问主内存”,缓存行只要处于有效状态,CPU会充分利用缓存提升读取效率,不会做无意义的主存访问。
这一结论的核心依据是:volatile的内存语义是“保证可见性”,而非“放弃CPU缓存优化”,JVM和CPU的设计会在保证可见性的前提下,尽可能利用缓存提升性能,二者并不冲突。
一、volatile读的真实内存语义:读前“验证缓存有效性”,而非“强制主存读”
之前我们讲过,JVM为volatile读操作插入LoadLoad+LoadStore内存屏障,但这两个内存屏障的核心作用并非“强制从主内存读取”,而是为了保证“读取volatile字段前,当前核心中该字段所在的缓存行一定是有效状态”,具体屏障行为可拆解为3点(无任何“强制绕开缓存”的逻辑):
- 强制处理CPU的无效队列:确保之前接收到的所有缓存行失效通知都已执行,不会存在“缓存行已失效但未标记”的情况;
- 禁止屏障两侧的指令重排:保证volatile读的有序性,不影响缓存的使用;
- 验证目标缓存行的有效性:检查当前核心L1/L2中该volatile字段所在的缓存行MESI状态——仅当缓存行为Invalid(失效)时,才会从L3共享缓存/主内存重新加载;若缓存行为Shared/Exclusive(有效),则直接从本地缓存读取。
简单说:volatile读的“从主内存加载”是「条件行为」(缓存失效时触发),而非「无条件行为」(每次必触发),内存屏障的核心是“兜底有效性”,而非“放弃缓存”。
二、未被改写时,volatile字段的缓存行始终处于有效状态
当volatile字段从未被任何线程修改时,基于MESI缓存一致性协议,该字段所在的缓存行会一直保持Shared(共享) 或Exclusive(独占) 有效状态,不会被标记为Invalid,原因如下:
- 缓存行的Invalid状态仅能由总线嗅探的失效通知触发,而失效通知是其他核心修改该字段时才会发送的硬件行为——无修改则无失效通知,缓存行状态不会主动变更;
- 线程循环读取volatile字段时,仅会触发缓存行的“读操作”,MESI协议规定:读操作不会改变有效缓存行的状态(Shared态的读仍为Shared,Exclusive态的读仍为Exclusive);
- 只要当前核心的缓存未被CPU缓存替换算法(如LRU)淘汰,该有效缓存行会一直驻留在L1/L2私有缓存中,供循环读取直接使用。
此时的物理执行流程非常简单(以单核心运行该线程为例):
- 第一次读取volatile字段:CPU按“L1→L2→L3→主存”顺序加载,最终将缓存行存入L1/L2,标记为Shared/Exclusive;
- 后续循环读取:直接检查L1缓存行状态为有效,无需任何主存/L3交互,直接从L1读取数据,性能与读取普通变量几乎无差异。
三、补充:volatile读可见性的核心保障,并非“每次主存读”
很多人会疑惑:“如果不从主存读,volatile的可见性怎么保证?”——这是对volatile可见性的核心误区,volatile读的可见性保障,不是“每次读主存的最新值”,而是“读前必保证缓存行是当前硬件层面的最新有效值”:
- 当字段未被改写时,缓存中的值就是主存的最新值,直接读缓存既高效又能保证可见性;
- 当字段被其他线程改写时,会触发总线嗅探的失效通知,将当前核心的缓存行标记为Invalid——此时下一次volatile读会因“缓存失效”,强制从L3/主存加载其他线程修改后的最新值,并重新将缓存行标记为有效。
简单说:volatile读的可见性是“失效必刷新,有效则复用”,既保证了“有修改时能读到最新值”,又避免了“无修改时反复访问主存的性能损耗”,是JMM对硬件缓存的合理利用,而非简单的“强制主存访问”。
四、特殊情况:缓存行被淘汰时,会从L3/主存重新加载
唯一的例外是:若线程循环读的时间极长,或当前核心的L1/L2缓存空间不足,该volatile字段的缓存行可能被CPU缓存替换算法淘汰(移出L1/L2)。此时下一次读取会触发“缓存未命中”,CPU会重新从L3共享缓存(若有)或主内存加载缓存行,但这一行为:
- 与volatile的语义无关,是CPU的通用缓存优化策略,普通变量的读取也会发生;
- 加载后的缓存行仍为有效状态,后续读取依然会复用缓存,并非每次都主存加载;
- L3共享缓存是多核共享的高速缓存,即使从L3加载,也远快于主内存访问。
一句话总结
volatile字段未被改写时,循环读不会每次从主内存读取,而是直接复用当前核心L1/L2中处于Shared/Exclusive有效状态的缓存行;volatile读的核心规则是“读前验证缓存有效性,失效才从主存/L3加载”,内存屏障和MESI协议共同保证了“可见性”和“缓存效率”的平衡,而非简单强制绕开缓存。

浙公网安备 33010602011771号