偏向锁重偏向触发条件是:jvm启用偏向锁、对象已偏向且原偏向线程已退出、同批对象被多个线程短时间频繁竞争导致反复撤销加锁。

偏向锁重偏向触发条件是什么
重偏向不是自动发生的,它只在满足三个硬性条件时才可能启动:
- 当前 JVM 启用了偏向锁(-XX:+UseBiasedLocking,JDK 6–8 默认开,JDK 15+ 默认关)
- 对象已进入偏向状态,且偏向线程已退出(比如线程结束或调用了 Object.wait())
- 同一批对象(同一类实例)在短时间内被多个不同线程竞争获取锁,且每次都是“先撤销再加锁”
为什么需要 Bulk Rebiasing 而不是逐个撤销
频繁撤销偏向锁代价很高:每次撤销要停顿所有线程(safepoint),还要遍历对象头、更新 Mark Word、刷新 CPU 缓存行。当一个对象池(如 ThreadLocal 缓存的 StringBuilder)被 1000 个线程轮流复用,逐个撤销会引发上百次 safepoint,拖慢吞吐。
Bulk Rebiasing 的做法是:把这批对象打上“可批量重偏向”标记,在下一次安全点统一处理——不撤销,直接改偏向线程 ID 和 epoch 值,跳过锁膨胀流程。
关键参数:
- -XX:BiasedLockingBulkRebiasThreshold=20:同一类对象被不同线程竞争达 20 次,触发批量重偏向
- -XX:BiasedLockingDecayTime=25000(毫秒):上次批量操作后,超时则清空统计,重新计数
重偏向失败的典型现象和原因
你看到日志里反复出现 Bulk rebiasing of [class] failed,大概率是以下之一:
- 对象已升级为轻量级锁(Mark Word 中锁标志位为 00),无法再重偏向 —— 此时只能走常规锁流程
- 类被设置为“永不偏向”,比如通过
-XX:BiasedLockingStartupDelay=0后又调用了Class.revokeBias(),或该类在启动后被显式禁用(Unsafe.revokeBias()) - 当前处于 GC safepoint 但 CMS 或 ZGC 正在并发标记,导致重偏向被跳过(JDK 8u40 后部分修复,但仍有窗口期)
怎么验证是否真在用重偏向
别只看参数开关,得看运行时行为:
立即学习“Java免费学习笔记(深入)”;
启动时加:-XX:+PrintBiasedLockingStatistics -XX:+UnlockDiagnosticVMOptions
运行一段时间后执行:jcmd <pid> VM.native_memory summary</pid> 或触发 jstat -compiler <pid></pid> 配合日志观察。
真正有效的信号是:
- 日志中出现 Bulk rebiasing <n> objects of type [class]</n>
- jstat -printcompilation <pid></pid> 显示 BiasedLocking 相关编译计数上升
- GC 日志里 safepoint 平均停顿时间未随对象复用频率明显增长
注意:JDK 10 开始默认关闭偏向锁,JDK 15 彻底移除;如果你用的是 JDK 17+,-XX:+UseBiasedLocking 已是无效参数,重偏向根本不会发生。










