synchronized退出同步块时,jvm强制将块内实际修改过的共享变量刷新回主内存,这是jmm规定的必须行为;通过storestore+storeload屏障禁止重排序,与锁释放共同构成happens-before关系,确保其他线程可见。

Java 变量在 synchronized 同步块中退出时刷入主内存,靠的是 JVM 自动插入的 StoreStore + StoreLoad 内存屏障,不是手动控制,也不依赖线程调度,而是 JMM 规定的强制行为。
同步块退出时的刷新是精准且确定的
只刷那些在块内被实际修改过的共享变量,不是全部字段都写回:
- 局部变量、未被其他线程访问的私有字段,不会触发刷新
- 即使某个 volatile 或普通字段在块内被多次读取,只要没被赋新值,就不会写回主内存
- JVM 通过静态分析和运行时跟踪识别“真正被写入”的变量,避免无谓带宽消耗
内存屏障如何保障刷新不被乱序
在 monitorexit 指令前,JVM 插入 StoreStore 屏障,确保两件事严格有序:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 所有同步块内已完成的写操作(如 x = 1、list.add(item))必须先完成并落主存
- 这些写不能被 JIT 编译器或 CPU 重排到锁释放之后
- StoreLoad 屏障进一步防止后续非同步代码的读/写提前穿插进来
刷新动作与 happens-before 关系直接绑定
这个写回不是孤立动作,它和锁释放共同构成 JMM 中的关键同步契约:
- 线程 A 退出 synchronized 块 → 修改刷入主内存 + 锁释放
- 线程 B 进入同一把锁的同步块 → 强制清空本地缓存副本 → 从主内存重新加载变量
- A 的写与 B 的读之间自动建立 happens-before,B 一定看到 A 的最新值
和 volatile 刷内存的区别在哪
两者都靠内存屏障,但作用粒度和语义不同:
- volatile 写:只刷该变量本身,用 StoreStore + StoreLoad,配合 MESI 失效其他核心缓存行
- synchronized 退出:刷块内所有被改过的共享变量,范围更广,且天然带互斥和原子性保证
- volatile 不提供原子性,synchronized 刷内存的同时也保证临界区执行的排他性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










