JMM是Java语言层面对多线程内存访问的抽象规范,核心解决可见性与有序性问题;它不直接依赖缓存一致性协议,而是通过volatile、synchronized等同步机制触发内存屏障,迫使底层硬件(如MESI协议)落实数据同步。

Java 中缓存一致性协议本身不直接“配合”JMM,而是JMM在语言层面抽象并约束了底层硬件(如CPU缓存)的行为。真正起作用的是:JMM定义了线程间共享变量的读写规则,而硬件(如MESI协议)负责在物理层面落实这些规则的可见性与有序性基础。两者是上下层协同关系——JMM提出“要什么”,硬件机制(含缓存一致性协议和内存屏障)负责“怎么做到”。
缓存一致性协议保障数据可见性的物理基础
MESI等协议确保多核CPU中对同一内存地址的缓存行状态同步。例如:
- 当线程A在核心1上修改一个变量,该缓存行进入Modified状态,其他核心中对应缓存行被标记为Invalid;
- 线程B在核心2上随后读取该变量时,发现本地缓存失效,必须从主内存或核心1的缓存重新加载最新值;
- 这就让“线程A改了,线程B能读到新值”成为可能——但前提是JMM要求这次读写必须构成一个“happens-before”关系,否则编译器或处理器仍可能重排或延迟刷新。
JMM用同步动作触发缓存协议生效
仅靠硬件协议不够,因为普通读写不会强制刷新或失效缓存。JMM规定了特定操作作为“同步点”,迫使工作内存与主内存交互,从而激活缓存一致性机制:
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
- volatile写:插入StoreStore + StoreLoad屏障,确保之前所有写操作完成,并将变量值立即刷入主内存,触发其他核心缓存失效;
- volatile读:插入LoadLoad + LoadStore屏障,强制从主内存或最新缓存重新加载,避免使用过期副本;
- synchronized释放锁:等价于一次volatile写,把临界区内的修改全部刷新到主内存;
- 线程start/join:建立线程启动前与执行后、终止前与join返回后的happens-before关系,隐含内存同步语义。
硬件优化带来的“陷阱”与JMM的补救
CPU为提升性能引入Store Buffer、Invalidate Queue等机制,反而可能削弱一致性:
立即学习“Java免费学习笔记(深入)”;
- 写操作先入Store Buffer再异步刷入L1,导致其他核心即使监听到失效请求,也看不到最新值(StoreLoad重排);
- MESI协议中Invalid消息可能排队延迟处理,造成短暂的不一致窗口;
- JMM通过内存屏障指令(如lock前缀、mfence)强制刷Buffer、等待Invalid完成,把不确定的硬件行为纳入可控范围。
不是所有变量都走这套流程
JMM只对“共享可变变量”的读写施加约束。局部变量、final字段(构造完成后)、无竞争的线程私有对象,不涉及跨线程通信,也就无需触发缓存一致性协议。只有当多个线程通过主内存交换状态时,JMM的规则和底层缓存协议才共同介入,形成从代码语义→字节码→JVM指令→CPU屏障→缓存状态转换的完整链路。

















