Java锁底层由OpenJDK的ObjectMonitor实现,synchronized直接操作其_owner、_EntryList和_WaitSet;Monitor仅在重量级锁时创建,偏向锁和轻量级锁不触发;其生命周期由JVM管理,不可显式控制;wait/notify必须在synchronized块内调用,本质是操作同一Monitor。

OpenJDK 的 Monitor 就是 Java 锁的底层实现载体
Java 中的 synchronized 不是语法糖,也不是 JVM 随意定义的逻辑——它直接绑定到 OpenJDK(HotSpot)里每个 Java 对象内置的 ObjectMonitor 实例。这个 C++ 类型的对象真实存在于堆中,由 JVM 在首次需要重量级锁时懒创建,并通过对象头的 Mark Word 指向它。换句话说:synchronized 块/方法执行时,真正操作的是 ObjectMonitor 的 _owner、_EntryList 和 _WaitSet 等字段。
Monitor 只在锁升级到重量级时才真正“出场”
很多人误以为每次 synchronized 都会立即分配 Monitor,其实不是:
- 无竞争时,偏向锁阶段:对象头
Mark Word仅存线程 ID 和偏向标志,不关联任何 Monitor - 轻量级锁阶段:用 CAS 替换栈中锁记录,仍不触发 Monitor 创建
- 只有当多个线程真实竞争、CAS 失败且自旋耗尽后,JVM 才会膨胀为重量级锁——此时才 new 出
ObjectMonitor,并把对象头的Mark Word改为指向该 Monitor 的指针
所以你在 jstack 或 JFR 中看到的 java.lang.Thread.State: BLOCKED (on object monitor),只会在重量级锁生效后出现;轻量级或偏向锁下,线程不会进入 OS 级阻塞,也不会显示 “on object monitor”。
Monitor 的生命周期不由 Java 代码控制
ObjectMonitor 是 JVM 内部管理的资源,开发者无法显式创建、销毁或引用它:
立即学习“Java免费学习笔记(深入)”;
- 没有对应的 Java 类,不能
new ObjectMonitor(),也不能强制 GC 它 - Monitor 被复用:一个对象释放重量级锁后,其 Monitor 不会立即销毁,可能被后续其他对象复用(取决于 JVM 实现和内存压力)
- Monitor 与对象解耦:一旦创建,即使原对象被 GC,只要还有线程在
_WaitSet或_EntryList中等待,Monitor 就必须继续存活
这也解释了为什么频繁触发锁升级/降级(比如短生命周期对象反复加锁)会增加 JVM 内存开销和同步延迟——Monitor 分配/回收本身有成本。
wait/notify 必须和 synchronized 配对使用,本质是操作同一个 Monitor
wait()、notify()、notifyAll() 这三个方法属于 Object 类,但它们**不能脱离 Monitor 独立工作**:
- 调用
obj.wait()前,当前线程必须已持有obj的 Monitor(即在synchronized(obj)块内),否则抛IllegalMonitorStateException - 执行
wait()时,JVM 实际是把当前线程从_owner移出,清空_count,然后插入_WaitSet队列 -
notify()并不“唤醒线程”,只是把一个线程从_WaitSet搬到_EntryList,最终能否获得锁,仍要参与和_EntryList中其他线程的公平竞争
这个细节常被忽略:哪怕你只调用 notify(),被唤醒的线程也未必能立刻执行——它得重新抢锁,而这时可能已有新线程正试图进入 synchronized 块。


















