synchronized块的内存冲刷本质是jvm在加锁时清空工作内存、解锁时写回主内存,通过loadload/loadstore和storestore/storeload屏障保障可见性与有序性,无需手动flush。

Java 中 synchronized 块的内存冲刷行为,本质是 JMM 通过隐式插入内存屏障来保障可见性与有序性,不是手动调用“冲刷”指令,而是由 JVM 在加锁/解锁时自动完成主内存与工作内存的数据同步。
synchronized 的加锁与解锁触发内存同步
进入 synchronized 块前(加锁),JVM 会强制线程清空本地工作内存中对应共享变量的缓存副本;退出 synchronized 块时(解锁),会把修改后的变量值立即写回主内存。这个过程确保了临界区内的读写操作对其他线程可见。
- 加锁时:清空工作内存 → 强制后续读取从主内存加载最新值
- 解锁时:刷新工作内存 → 强制将变更同步到主内存
- 该机制不依赖 volatile,但效果上覆盖了 volatile 的可见性保证
内存屏障如何支撑这一冲刷行为
synchronized 并非直接执行“写回主存”动作,而是依靠底层内存屏障约束指令重排序,并配合缓存一致性协议(如 MESI)实现跨核数据可见。具体屏障语义如下:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 进入同步块:插入 LoadLoad + LoadStore 屏障 → 防止后续读写被重排到锁获取之前
- 退出同步块:插入 StoreStore + StoreLoad 屏障 → 确保所有写操作在解锁前完成,并对其他线程可见
- StoreLoad 屏障是关键,它阻止了读操作越过写操作,从而让其他线程在获取同一把锁时能观察到此前的全部写结果
对比 volatile 理解 synchronized 的“冲刷”强度
volatile 只在单个变量读写上插入轻量级屏障(读插入 LoadLoad+LoadStore,写插入 StoreStore+StoreLoad),而 synchronized 是对整个代码块施加重量级同步语义:
- volatile 不保证原子性(如 count++ 仍需 synchronized)
- synchronized 既保证可见性,又保证原子性,还天然具备互斥能力
- 它的“冲刷”是块级的、强一致的,且以 monitor 为边界,比 volatile 的字段级可见性更彻底
实际编码中不需要显式控制冲刷时机
开发者无需调用 flush 或 sync 方法——只要把共享状态的读写包裹在 synchronized 块内,JMM 就会在正确位置插入屏障并触发内存同步。例如:
public synchronized void setDone() { done = true; } // 解锁时自动冲刷 done 到主内存若用普通变量或仅 volatile 修饰 done,其他线程可能长期看不到 true;而 synchronized 确保一旦 setDone 返回,所有 CPU 核心都能在下一次读取时看到更新。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










