synchronized 通过锁的获取与释放建立 happens-before 关系来间接保证有序性:线程 A 释放锁前的写操作对线程 B 获取锁后的读操作可见,且禁止相关指令重排序。

synchronized 本身不直接保证代码块的“有序性”,它保证的是**互斥访问**和**可见性**,而“有序性”在 Java 内存模型(JMM)中是通过锁的获取与释放建立的 happens-before 关系间接实现的——这能阻止指令重排序对多线程可见结果的影响。
锁的获取与释放构成 happens-before 关系
Java 规范规定:对同一个锁,线程 A 释放锁的操作,happens-before 线程 B 后续获取该锁的操作。这意味着:
- A 在释放锁前对共享变量的所有写操作,对 B 获取锁后的读操作可见;
- JVM 和 CPU 不会把 A 锁内写操作重排序到释放锁之后,也不会把 B 锁内读操作重排序到获取锁之前;
它不保证代码执行的绝对时间顺序
synchronized 不控制线程调度,也不决定哪个线程先抢到锁。例如:
两个线程同时竞争同一把锁,谁先执行 synchronized 块取决于操作系统调度和锁竞争结果,不是代码书写顺序。所谓“有序”,是指:一旦某个线程进入临界区,它看到的共享变量状态一定是之前持有该锁的线程所留下的最新一致状态,而不是中间态或过期值。
配合 volatile 或 final 才能强化初始化有序性
仅靠 synchronized 无法解决对象构造过程中的重排序问题(如 DCL 单例中的指令重排)。例如:
- 若一个线程在 synchronized 块中新建对象并赋值给静态变量,另一个线程在 synchronized 外读取该变量,仍可能看到未完全构造的对象;
- 此时需将引用声明为 volatile,利用 volatile 写-读的 happens-before 保证构造完成后再发布;
- 或确保对象内部状态用 final 字段定义,借助 final 字段的初始化安全保证。
小结:synchronized 的“有序”是同步语义带来的副作用
它不提供类似 Thread.join() 或 CountDownLatch 那样的显式执行顺序控制,而是通过加锁/解锁动作,在共享变量读写之间建立可靠的内存可见边界。真正起作用的是 JMM 定义的锁规则,不是 synchronized 关键字本身做排序。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











