synchronized通过JMM的happens-before规则和内存屏障保障可见性:进入同步块前清空工作内存并重读主内存,退出时强制刷新修改到主内存。

synchronized 通过 Java 内存模型(JMM)规定的锁语义,在加锁与解锁的边界上强制同步工作内存与主内存,从而天然保障多线程间的可见性。它不依赖额外声明,也不靠轮询或延迟,而是由 JVM 在运行时插入内存屏障来确保数据及时更新和读取。
进入同步块前:强制重读主内存最新值
当一个线程准备执行 synchronized 代码块时,必须先获取锁。在获得锁的瞬间,JVM 会要求该线程:
- 清空自身工作内存中与该锁关联的所有共享变量副本;
- 从主内存中重新加载这些变量的最新值。
这意味着,无论其他线程之前是否修改过某个变量,只要它是在同一把锁保护下完成的,当前线程进入临界区时就一定能“看到”那个新值。例如,线程 A 将 flag = true 写入并释放锁后,线程 B 下次进入同一把锁的同步块时,读到的一定是 true,而不是旧的缓存值。
退出同步块时:强制刷新修改回主内存
线程执行完同步块内的逻辑、准备释放锁前,JVM 会触发一次写同步操作:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 将工作内存中所有被修改过的共享变量,全部刷新回主内存;
- 确保这些变更对后续获取同一把锁的其他线程立即可见。
这个机制形成“读–改–写”的完整闭环。比如多个线程反复调用 synchronized void increment() { count++; },每次自增后的 count 值都会被及时刷出,不会因缓存滞留导致其他线程读到过期数字。
底层靠 happens-before 和内存屏障协同保障
可见性不是凭空实现的,而是建立在 JMM 的两条关键规则之上:
- unlock happens-before 后续 lock:线程 A 解锁前的所有写操作,对线程 B 后续加同一把锁后的读操作可见;
- 加锁/解锁处插入内存屏障:防止编译器或 CPU 把临界区内的读写指令重排到锁外,破坏“先写后读”的逻辑顺序。
这两者共同作用,让 synchronized 不仅能阻塞并发,还能让变量更新“看得见、来得及、不乱序”。
对比 volatile:作用粒度不同
volatile 也能保证可见性,但它只针对单个变量的读写生效,且不提供互斥;synchronized 是以整个临界区为单位:
- volatile 让“变量更新看得见”,但无法阻止两个线程同时执行 i++ 这类复合操作;
- synchronized 让“一段逻辑执行得干净又透明”,既锁住执行权,又统一管理所有涉及变量的内存同步。
所以,当需要保证多个变量协同更新、或包含多步操作的逻辑一致性时,synchronized 是更可靠的选择。

















