objectmonitor是hotspot jvm用c++实现的重量级锁核心,位于本地内存而非java堆,对象仅在发生竞争或调用wait()时才懒加载绑定;其通过_owner、_entrylist和_waitset三个字段协作管理线程竞争与等待。

Java 中的锁机制不是靠 Java 代码实现的魔法,而是 JVM 在底层用 C++ 构建的一套同步设施——ObjectMonitor。它不暴露给开发者,也不在 Java 堆里,而是分配在 JVM 的本地内存中,每个对象在真正需要重量级锁时才“懒加载”绑定一个。
ObjectMonitor 是什么,它在哪里
ObjectMonitor 是 HotSpot 虚拟机中的一个 C++ 类,不是 Java 类,不能 new,也不能被直接引用。它和 Java 对象是松耦合关系:对象刚创建时并不立即拥有 Monitor;只有当发生真实竞争(比如多个线程抢同一把锁)或调用了 wait() 等方法时,JVM 才会初始化并关联它。
此时,对象头 Mark Word 里的内容会被更新为指向这个 ObjectMonitor 实例的指针。也就是说,Monitor 不是对象的一部分,而是对象背后的“守门人”。
核心字段怎么协作
ObjectMonitor 内部靠三个关键字段协调线程行为:
- _owner:记录当前持有锁的线程指针。为 null 表示无人占有;非 null 时即表示该线程已进入临界区。
-
_EntryList:链表结构,存放调用
synchronized失败、正在等待获取锁的线程(处于 BLOCKED 状态)。 -
_WaitSet:链表结构,存放执行了
obj.wait()后释放锁并挂起的线程(处于 WAITING 状态),只能由notify()或notifyAll()唤醒。
注意:notify() 唤醒的线程不会直接拿到锁,而是从 _WaitSet 移到 _EntryList,重新参与锁竞争。
加锁和释放锁的实际流程
当线程执行 synchronized(obj) 时,JVM 并不直接操作 obj,而是走一套状态驱动的路径:
- 先检查对象头 Mark Word 的锁状态:如果是无锁、偏向锁或轻量级锁,就尝试用 CAS 或线程 ID 比较完成快速加锁,绕过 ObjectMonitor。
- 一旦自旋失败或发生 wait/notify,就会触发锁膨胀,升级为重量级锁,此时才真正初始化 ObjectMonitor,并把 Mark Word 改为指向它的指针。
- 进入重量级阶段后,线程通过 CAS 尝试将
_owner设为自己;失败则把自己封装成ObjectWaiter插入_EntryList,再调用操作系统原语(如pthread_cond_wait)休眠。 - 持有锁的线程退出时,会清空
_owner,然后从_EntryList挑一个线程唤醒(通常 FIFO),让它重新尝试抢锁。
monitorenter 和 monitorexit 指令的作用
编译器把 synchronized 块转成一对字节码指令:monitorenter 在入口执行,monitorexit 在所有出口(包括正常 return 和异常路径)插入。JVM 解释或 JIT 执行这些指令时,最终都映射到 ObjectMonitor 的 enter() 和 exit() 方法。
方法级 synchronized 的锁获取更早,在方法调用开始前由 JVM 自动插入 monitorenter;而同步代码块的锁获取发生在执行到大括号那一行。这也意味着方法锁更容易因提前 return 或异常导致锁持有时间不可控。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











