文章目录

Java偏向锁撤销时的安全点停顿问题分析

发布于 2026-04-27 04:19:44 · 浏览 3 次 · 评论 0 条

Java偏向锁撤销时的安全点停顿问题分析

Java偏向锁是为了在无竞争情况下减少获取锁性能损耗而引入的优化机制,它假设锁通常由同一线程多次获得。然而,一旦出现第二个线程尝试获取锁,偏向锁就必须撤销,这个过程并非瞬间完成,而是依赖于JVM的全局安全点,这会导致系统性能出现不可预测的停顿。


一、 理解偏向锁撤销的核心机制

偏向锁的撤销过程并不是持有锁的线程主动“释放”操作,而是在竞争发生时,由JVM强制介入进行的。最关键的性能瓶颈在于,撤销操作必须等待一个“全局安全点”。

在这个安全点上,所有正在运行的线程都必须暂停执行。这种“Stop-The-World”式的停顿是为了确保在修改对象头Mark Word状态时,没有线程正在读写该对象,从而保证数据的一致性。

当检测到需要撤销偏向锁时,JVM会执行以下核心逻辑:

  1. 暂停所有线程,到达全局安全点。
  2. 检查持有偏向锁的线程(线程A)是否仍然存活。
  3. 遍历线程A的栈帧,确认其是否仍处于同步代码块中。

二、 偏向锁撤销的详细流程

为了更直观地理解安全点停顿期间发生的事情,我们需要理清撤销的具体判断路径。以下流程图描述了从竞争出现到最终锁状态确定的完整逻辑:

graph TD Start[线程B尝试获取偏向锁] --> CAS{CAS替换
Thread ID} CAS -- 成功 --> GetLock[线程B获得偏向锁] CAS -- 失败 --> Trigger[触发偏向锁撤销] Trigger --> SafePoint[等待全局安全点] SafePoint --> PauseWorld[暂停所有线程 STW] PauseWorld --> CheckAlive{持有锁的线程A
是否存活?} CheckAlive -- 未存活 --> ResetBias[重置对象为无锁状态] ResetBias --> Compete[线程B竞争轻量级锁] CheckAlive -- 存活 --> CheckLock{线程A是否在
同步代码块中?} CheckLock -- 不在 --> RevokeBias[撤销偏向锁
设为无锁状态] RevokeBias --> Compete CheckLock -- 在 --> Upgrade[升级为轻量级锁] Upgrade --> WakeA[唤醒线程A持有轻量级锁] WakeA --> WaitB[线程B自旋等待]

根据上述逻辑,在安全点停顿期间,JVM主要执行以下具体操作步骤:

  1. 定位持有该偏向锁的线程。
  2. 判断该线程的状态:
    • 如果线程已经结束执行(不再存活),直接将对象头Mark Word设置为无锁状态。
    • 如果线程仍然存活,继续检查栈帧。
  3. 扫描存活线程的栈帧:
    • 如果发现该线程已经退出了同步代码块(即Lock Record中不再持有该锁对象),则判定可以撤销偏向锁,将对象恢复为无锁状态。
    • 如果发现该线程仍在同步代码块中,说明锁正在被使用。
  4. 处理正在使用的锁:
    • 此时不能直接撤销,必须将偏向锁升级为轻量级锁。
    • JVM会遍历线程栈中所有相关的Lock Record,将其修复为轻量级锁所需的Displaced Mark Word格式,并替换对象头的指针指向栈中的Lock Record。
  5. 恢复执行:唤醒所有暂停的线程,持有锁的线程继续以轻量级锁执行,竞争的线程进入自旋等待状态。

三、 安全点停顿带来的性能影响

偏向锁撤销的最大性能开销在于“到达安全点”和“暂停所有线程”这两个步骤。

  • 到达安全点的延迟:JVM并不会随时随意暂停线程,它需要等待所有线程执行到特定的“安全点”位置(通常是循环回边、方法返回等位置)。如果某个线程正在执行长时间的计算且没有安全点检查,整个撤销过程就会被显著拖长,导致竞争线程长时间等待。
  • 批量撤销的震动:如果一个类的大量对象都经历了撤销过程,JVM会触发“批量重偏向”或“批量撤销”。这意味着针对该类的后续对象,JVM可能会彻底禁用偏向锁,导致所有的同步操作都直接进入轻量级锁逻辑,反而增加了CAS操作的开销。

四、 针对性优化与配置建议

在实际生产环境中,如果系统存在高并发的锁竞争,偏向锁的撤销机制往往会成为性能累赘而非优化手段。我们可以根据场景调整JVM参数来规避安全点停顿带来的问题。

检查当前应用是否属于高并发竞争场景,如果同步代码块经常被多个线程交替访问,建议关闭偏向锁。

关闭偏向锁的JVM参数如下:

-XX:-UseBiasedLocking

如果希望保留偏向锁但调整其启动延迟(偏向锁默认在JVM启动几秒后才开始生效,为了避免启动时的竞争),可以设置以下参数:

-XX:BiasedLockingStartupDelay=0

监控应用日志,如果频繁出现 BiasedLocking 相关的打印信息或者观察到长时间的 Stop-The-World 停顿(通常可以通过GC日志或安全点日志分析),应当果断禁用该特性,转而依赖轻量级锁的自旋机制来处理并发。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文