synchronized通过内存屏障和monitor语义保证有序性:monitorenter前插入loadload+loadstore屏障,monitorexit后插入storestore+loadstore屏障,并依托owner切换形成强顺序锚点,实现块级有序。

synchronized 保证有序性,靠的不是“加个锁就自动按顺序执行”,而是通过内存屏障(Memory Barrier)和 JVM 对 Monitor 的语义约束,强制限制指令重排范围,并确保临界区内的操作对其他线程呈现一致的执行顺序。
有序性本质:禁止特定范围的指令重排
Java 允许编译器和 CPU 在不改变单线程语义的前提下重排指令,但多线程下可能破坏逻辑。synchronized 不是全局禁用重排,而是在进入和退出同步块时插入两类内存屏障:
- monitorenter 前:插入 LoadLoad + LoadStore 屏障,防止临界区内的读/写操作被提到锁获取之前
- monitorexit 后:插入 StoreStore + LoadStore 屏障,防止临界区内的写操作被拖到锁释放之后
这使得同步块内部的代码,在本线程看来是按源码顺序执行;在其他线程看来,只要它们也通过同一把锁进入临界区,就能看到这些操作以可预测的、与代码书写一致的顺序发生。
Monitor 机制强化执行边界
每个 synchronized 块或方法都关联一个 Monitor。JVM 规定:线程只有成为 Monitor 的 Owner 才能执行临界区代码;而 Owner 的切换本身就是一个同步点。这就天然形成两个强顺序锚点:
- 前一个线程释放锁(Owner 置空)→ 后一个线程成功获取锁(Owner 更新)→ 后一个线程开始执行
- 该顺序由 JVM 和操作系统协同保障,不可被绕过或乱序
这种“锁获取-执行-锁释放”的三段式结构,使多个线程对同一临界区的访问呈现出串行化效果,从而在宏观上维持了逻辑上的执行顺序。
与 volatile 的有序性区别
volatile 仅在变量读写处插入轻量级屏障(LoadLoad/StoreStore),只约束该变量相关的重排;而 synchronized 的屏障作用于整个临界区,覆盖所有读写操作,且附带互斥语义。因此:
- volatile 能禁止“某变量读”与“其后任意读写”的重排,但不能保证复合操作(如 i++)的顺序原子性
- synchronized 把整段代码“打包”成一个不可分割的执行单元,既禁重排,又保原子,还强可见
换句话说,synchronized 的有序性是“块级有序”,volatile 是“字段级有序”。
字节码与运行时协同生效
编译期将 synchronized 块转为 monitorenter / monitorexit 指令;运行期 JVM 在解释或 JIT 编译时,根据锁状态(偏向/轻量/重量级)动态注入对应屏障指令。例如:
- 轻量级锁基于 CAS 和栈帧 Lock Record,屏障由 HotSpot 内部硬编码插入
- 重量级锁依赖 OS mutex,其系统调用本身带有全内存屏障语义
无论锁处于哪种状态,JVM 都确保有序性语义不丢失——这是 synchronized 可靠性的底层根基之一。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











