偏向锁撤销成本高,因其需全局安全点停顿并遍历所有线程栈帧查找锁记录,时间复杂度为O(N×M),且受长循环或JNI阻塞影响,易引发不可控STW延迟。

偏向锁撤销成本高,核心在于它需要全局安全点(safepoint)停顿,并遍历所有线程的栈来检查是否持有该锁——这不是简单的标志位修改,而是涉及JVM底层线程状态扫描的重量级操作。
偏向锁撤销必须进入安全点
JVM只有在安全点才能保证线程处于可控状态(比如刚好在方法调用边界、循环末尾等),此时才能安全地检查其栈帧中是否存有该对象的锁记录。这意味着:
- 所有Java线程必须暂停执行,等待当前正在运行的线程到达下一个安全点
- 若某个线程正执行长循环或本地代码(JNI),可能长时间无法进入安全点,导致撤销被阻塞
- 停顿时间不可控,尤其在高负载、多线程场景下,可能引发明显STW(Stop-The-World)延迟
需逐线程扫描栈帧查找锁记录
撤销偏向锁时,JVM要确认:有没有线程把该对象当作偏向锁持有?这要求:
- 对每个存活Java线程,解析其Java栈的所有栈帧
- 在每个栈帧的Lock Record(锁记录)中比对对象头地址和线程ID
- 一旦发现匹配,就要将其升级为轻量级锁(重置Mark Word,并在栈中补全Displaced Mark Word)
批量撤销与禁用机制反而暴露成本问题
当JVM检测到某类对象频繁发生偏向撤销(如锁竞争激烈),会触发批量撤销(Bulk Revoke)或直接禁用该类的偏向锁。但这本身也依赖统计+全局同步:
- 需要在安全点采集足够多的撤销事件样本
- 批量操作仍需再次停顿,统一修改类元数据中的“是否允许偏向”标志
- 禁用后,新实例直接走轻量级锁路径,但已偏向的对象仍需逐个撤销——旧账没清完,新策略就上马
对比其他锁状态转换更轻量
轻量级锁膨胀为重量级锁虽然也要升级,但只需:
- 原子修改对象头指向Monitor指针(CAS操作)
- 将当前线程的锁记录链挂到Monitor的EntryList
- 全程无需安全点,也不扫描其他线程栈
基本上就这些。偏向锁本意是优化无竞争场景,但一旦出现竞争,它的“反向清理”就成了性能陷阱。










