synchronized底层依赖objectmonitor,竞争失败时线程被封装为objectwaiter加入_entrylist并调用os::park()陷入内核态blocked;释放锁时通过os::unpark()唤醒线程,全程由操作系统完成挂起/唤醒,jvm仅协调。

Java 中的 synchronized 在底层依赖对象的监视器(Monitor),当线程竞争锁失败时,并不是由 JVM 直接“挂起”线程,而是通过操作系统提供的互斥原语(如 mutex、condition variable)配合 JVM 的 Monitor 实现阻塞与唤醒。所谓“重量级锁”,特指锁膨胀到依赖操作系统线程调度的状态——此时线程会进入 BLOCKED 状态,并真正让出 CPU。
对象监视器(Object Monitor)的本质
每个 Java 对象在 HotSpot 虚拟机中都关联一个 ObjectMonitor 结构(位于 C++ 层),它包含:
- _owner:指向当前持有锁的线程(或 null)
- _EntryList:等待获取锁的线程队列(双向链表),处于 BLOCKED 状态
-
_WaitSet:调用
wait()后挂起的线程队列(处于 WAITING/TIMED_WAITING) - 计数器(_count):记录重入次数
当线程执行 synchronized(obj) 时,JVM 会尝试原子地将 _owner 设为当前线程。若失败(已有线程持有),则进入争用逻辑。
线程如何被挂起(进入 BLOCKED)
挂起不是 JVM 自己调用 Thread.suspend()(该方法已废弃且不安全),而是通过以下协作完成:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- JVM 检测到锁竞争后,把当前线程封装成
ObjectWaiter,插入_EntryList - 调用底层
os::PlatformEvent::park()(Linux 上基于 futex,Windows 上基于 CreateEvent/SleepConditionVariableCS) - 该系统调用会使线程陷入内核态等待,释放 CPU,状态变为 BLOCKED
- 线程不再参与用户态调度,直到被其他线程显式唤醒(如 notify/notifyAll)或锁释放后被 Monitor 选中
锁释放时如何唤醒等待线程
当持有锁的线程退出同步块,JVM 执行 monitor exit 流程:
- 将
_owner置为 null - 若
_EntryList非空,从中取出一个ObjectWaiter,将其对应线程设为新_owner - 调用
os::PlatformEvent::unpark(thread)唤醒该线程(Linux 上触发 futex_wake) - 被唤醒线程从 park 返回,重新尝试获取锁;若成功,进入 RUNNABLE 状态继续执行
注意:挂起/唤醒是操作系统级行为
关键点在于:挂起线程的是操作系统内核,不是 JVM 解释器或 JIT 代码。JVM 只是协调者——它维护 Monitor 数据结构、排队、调用 OS 接口。这也是为什么重量级锁开销大:每次 park/unpark 都涉及用户态→内核态切换、上下文保存/恢复、调度器介入。
现代 HotSpot 会尽量避免走到这一步:偏向锁 → 轻量级锁(CAS 自旋)→ 重量级锁,只有自旋失败且竞争持续时才膨胀。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










