synchronized 的底层实现依赖 JVM Monitor 机制,通过对象头 Mark Word 锁标志位(01/00/10)标识无锁、偏向锁、轻量级锁、重量级锁状态,并借助操作系统互斥锁完成线程阻塞与唤醒。

synchronized 的底层实现依赖于 JVM 的监视器(Monitor)机制,核心是操作系统提供的互斥锁(Mutex Lock)与 Java 对象头中的锁标记配合完成的。
对象头与锁标志位
每个 Java 对象在堆中都有一个对象头(Object Header),其中包含 Mark Word。Mark Word 在 64 位 JVM 中通常为 8 字节,存储哈希码、GC 分代年龄、线程 ID、锁状态等信息。synchronized 初次加锁时,JVM 会尝试将 Mark Word 中的锁标志位设为“01”(未锁定),并记录偏向线程 ID(若开启偏向锁);否则进入轻量级锁流程。
- 无锁状态:Mark Word 存储对象哈希码或 GC 信息,锁标志位为 01
- 偏向锁:线程 ID 写入 Mark Word,标志位仍为 01,但第 3 位为 1
- 轻量级锁:Mark Word 被替换为指向线程栈中 Lock Record 的指针,标志位变为 00
- 重量级锁:Mark Word 指向 Monitor 对象地址,标志位变为 10
Monitor 对象与操作系统交互
Monitor 是 JVM 内部的同步组件,每个对象关联一个 Monitor 实例(由 C++ 实现,位于 HotSpot 的 ObjectMonitor 类中)。当锁升级为重量级,线程需调用操作系统提供的 mutex(如 Linux 的 pthread_mutex_t)来阻塞和唤醒。
- 线程调用 monitorenter 指令时,JVM 尝试获取 Monitor 的 _owner 字段
- 若 _owner 为空,CAS 设置为当前线程,成功则持有锁
- 若已被占用,线程进入 _EntryList 队列并挂起(调用 os::pthread_mutex_lock)
- 释放锁时(monitorexit),唤醒 _EntryList 中的一个线程,或转移至 _WaitSet(notify/notifyAll 场景)
锁膨胀过程(锁升级)
JVM 默认启用锁优化策略,锁状态会随竞争程度逐步升级,但不会降级:
立即学习“Java免费学习笔记(深入)”;
- 偏向锁:适用于单线程反复进入同一同步块,避免 CAS 开销;有线程竞争时撤销并升级
- 轻量级锁:适用于短时间、低竞争场景,用 CAS 替换 Mark Word 实现自旋获取
- 重量级锁:高竞争下,自旋失败后线程阻塞,交由 OS 调度,开销最大但公平性好
字节码与运行时协作
编译器将 synchronized 代码块转为 monitorenter / monitorexit 字节码指令。JVM 运行时解释或 JIT 编译后,这些指令最终触发上述锁逻辑。值得注意的是:
- monitorexit 不仅在正常退出时执行,异常出口也由编译器插入,确保锁释放
- JIT 编译可能进行锁消除(Lock Elision)或锁粗化(Lock Coarsening),实际执行未必对应原始代码结构
- wait()/notify() 操作必须在已获得 Monitor 的线程中调用,否则抛出 IllegalMonitorStateException


















