在多线程高竞争的服务端应用中,JVM默认开启的偏向锁本意是优化无竞争场景下的加锁开销,但当大量线程频繁访问同一监视器时,偏向锁的撤销机制反而会成为性能抖动的源头。这种抖动通常表现为每隔数秒出现一次几十毫秒甚至上百毫秒的停顿,监控曲线呈锯齿状,而普通CPU利用率指标却看不出异常。理解偏向锁撤销在JVM内部的执行路径,是分析此类问题的第一步。

偏向锁撤销的底层原理与安全点停顿
偏向锁的核心思想是:如果一个监视器对象被某个线程首次获取,JVM会在对象头中记录该线程ID,此后该线程再次进入同步块时只需比对线程ID而无需原子指令。但当另一个线程尝试获取已被偏向的锁时,JVM必须执行偏向撤销。撤销操作并非简单修改标记,它要求持有偏向锁的线程到达安全点,由虚拟机暂停所有相关线程后,再决定是否将锁升级为轻量级锁或重量级锁。
在HotSpot中,偏向锁撤销分为撤销和重偏向两类。单次撤销只影响一个对象,但JVM引入了批量撤销与批量重偏向的阈值机制。当某个类的对象发生偏向撤销次数达到阈值,例如二十次,该类后续新对象将直接禁用偏向;若达到另一阈值则触发批量重偏向。问题在于,这些批量操作都需要在全局安全点执行,高竞争下类级别的批量撤销会瞬间挂起所有线程,造成明显的STW停顿。
我们可以通过对象头布局理解这一过程。开启偏向锁后,对象头Mark Word包含是否偏向、锁标志位与线程指针。撤销时,JVM要遍历当前持有线程的栈帧找到锁记录,并清理相关偏向信息。如果此时系统正处于高竞争,每秒成千上万次错误偏向叠加,撤销线程与安全点协调的成本会远大于轻量级锁本身的CAS开销,此时偏向锁已经从优化变成了负担。
使用JFR与GC日志定位撤销热点
要确认性能抖动是否由偏向锁撤销引起,最直接的方式是开启Java Flight Recorder。JFR中提供了jdk.BiasedLockRevocation和jdk.BiasedLockClassRevocation事件,能够记录每次撤销发生的类、线程与持续时间。在JMC中过滤这些事件,若发现同一类频繁出现且伴随安全点事件jdk.Safepoint的长时间暂停,即可锁定问题根源。
除了JFR,还可以在启动参数中加入-XX:+PrintBiasedLockingStatistics与-XX:+TraceBiasedLocking。前者在JVM退出时打印各类的偏向与撤销计数,后者则在运行时输出撤销决策细节。下面是一段用于开启诊断参数的示例:
java -XX:+UseBiasedLocking
-XX:+PrintBiasedLockingStatistics
-XX:+TraceBiasedLocking
-XX:+UnlockDiagnosticVMOptions
-jar high-contention-service.jar
对于已上线且不能频繁重启的系统,可以借助jstack周期性采样,观察线程是否大量阻塞在ObjectMonitor::enter或安全点轮询。如果发现很多线程栈顶显示偏向锁相关内部方法,再结合监控中的停顿时间点,就能建立撤销与抖动的因果关联。需要注意的是,安全点停顿本身可能由其他原因引起,必须交叉比对JFR中的偏向锁事件时间戳。
高竞争场景下的调优与替代方案
一旦确认偏向锁撤销是抖动主因,最简单的做法是关闭偏向锁。从JDK 15开始偏向锁已被标记为废弃,而在早期版本中可使用-XX:-UseBiasedLocking直接禁用。关闭后,所有锁从一开始走轻量级锁路径,虽在无竞争时多了一次CAS,但彻底消除了撤销带来的安全点风险。对于高竞争系统,这通常是正向收益。
如果业务必须使用旧JDK且不能全局关闭,可通过-XX:BiasedLockingStartupDelay=0配合类级别的排除。例如使用-XX:CompileCommand=exclude或白名单机制减少特定热点类的偏向。但从工程角度看,高竞争下更合理的结构是减少共享监视器:用并发容器替代同步块、将锁拆分为分段锁、或采用无锁算法。下面示例展示用ReentrantLock配合tryLock降低阻塞:
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private long value = 0;
public boolean add(long delta) {
if (lock.tryLock()) {
try {
value += delta;
return true;
} finally {
lock.unlock();
}
}
return false;
}
}
最后要强调的是,偏向锁撤销的性能抖动具有隐蔽性,它不会抛异常也不会显著增加CPU占用,仅靠APM的响应时间百分位就能察觉。建议高竞争系统在压测阶段就开启JFR做基线采集,对比开启与关闭偏向锁的P99延迟。当看到批量撤销事件消失且长尾延迟下降,便说明调优生效。架构层面则应持续审视同步粒度,让JVM的锁机制运行在它擅长的低竞争区间。
Biased_Locking偏向锁撤销JVM性能分析修改时间:2026-08-18 06:14:28