重量级锁性能开销大,根本在于Monitor机制深度绑定操作系统内核,导致频繁用户态/内核态切换、ObjectMonitor复杂结构引发缓存失效与竞争、上下文切换带来CPU与缓存损耗;锁升级只是竞争显性化的触发器,而非根源。

重量级锁的性能开销,核心就落在 Monitor 机制与操作系统内核的深度绑定 上。它不是纯 Java 层的逻辑控制,而是把线程调度、阻塞、唤醒这些事,全权交给了操作系统来处理——这正是开销大的根本原因。
用户态与内核态切换频繁
Java 线程在用户态运行,但一旦要挂起或唤醒,就必须进入内核态调用系统服务(比如 Linux 的 pthread_mutex_lock/unlock)。每次切换涉及寄存器保存、栈切换、权限检查等,耗时通常在 几微秒到几十微秒。当多个线程激烈竞争同一把锁时,这种切换会反复发生:
- 线程 A 持有锁,线程 B/C/D 尝试获取 → 全部陷入阻塞 → 四次用户态→内核态切换
- 线程 A 释放锁 → 操作系统从等待队列选一个线程唤醒 → 至少一次内核态→用户态切换
- 若被唤醒的线程又没抢到锁(非公平竞争),可能立刻再次阻塞 → 又一轮切换
Monitor 内部结构放大调度成本
ObjectMonitor 不是轻量数据结构,它维护了多个线程队列和状态字段:
-
_EntryList存放阻塞中、等待获取锁的线程(Blocked 状态) -
_WaitSet存放调用wait()后释放锁并进入等待的线程(Waiting 状态) -
_cxq(竞争队列)临时缓存刚到来的竞争者,需链表操作和锁保护 -
_owner字段变更、_count计数更新等,都需原子操作或临界区保护
这些操作本身不重,但叠加在每次锁争用的路径上,尤其在高并发下,会加剧 CPU 缓存行失效(false sharing)、锁竞争和调度延迟。
上下文切换带来隐性损耗
线程被挂起后,操作系统需将其从 CPU 调度器移出,保存完整上下文(寄存器、浮点单元、MMU 状态等);唤醒时再恢复。这个过程:
- 消耗 CPU 周期,挤占本可用于业务计算的资源
- 导致 L1/L2 缓存局部性丢失,新唤醒线程首次执行常触发大量 cache miss
- 在容器或云环境里,还可能受 CPU 配额限制,进一步拉长响应时间
锁升级是开销的“触发器”,不是根源
很多人误以为“锁升级成重量级才开始慢”,其实不然。轻量级锁失败本身已暴露竞争压力,而升级只是把问题显性化:当 CAS 自旋多次失败,JVM 判定“靠自旋抢不到,不如让线程睡一会”,于是构造 Monitor、关联对象头、转入内核等待——真正昂贵的,是后续每一次锁获取/释放所引发的操作系统介入。


















