批量重偏向是JVM自动触发的优化机制,当某类对象偏向撤销达20次阈值时,仅一次safepoint停顿即可更新epoch并批量修正Mark Word,避免频繁STW,显著降低延迟。

偏向锁批量重偏向不是靠“主动触发”,而是 JVM 在运行中自动识别到一类对象的偏向撤销过于频繁后,为减少反复撤销开销而采取的优化动作。它本身不直接“提升性能”,但能显著避免因大量单个偏向锁撤销带来的 STW(Stop-The-World)暂停和 CPU 浪费,从而在特定场景下稳定吞吐、降低延迟。
批量重偏向发生的典型场景
当一个类(class)的对象被某一线程长期持有偏向锁,之后另一批线程频繁尝试获取这些对象的锁时,就会引发大量偏向撤销操作。例如:
- 服务启动初期,初始化阶段由主线程创建了数千个缓存对象并加了同步块(触发偏向);
- 后续业务线程批量访问这批对象作为锁目标,每次都要撤销原偏向,代价叠加;
- JVM 检测到该 class 的撤销计数达到默认阈值 20 次,就启动批量重偏向。
它是怎么减少开销的
单次偏向撤销需等待安全点(safepoint),暂停所有线程,再修改对象 Mark Word —— 这是重量级操作。而批量重偏向只做一次 safepoint 停顿,完成两件事:
- 将该 class 的 epoch 值 +1;
- 遍历所有线程栈,把当前已偏向且属于该 class 的对象,统一更新其 Mark Word 中的 epoch 字段。
之后新线程再尝试获取锁时,发现 epoch 不匹配,不再执行撤销流程,而是直接用 CAS 把 Thread ID 改成自己 —— 整个过程在用户态完成,无 safepoint 开销。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
哪些情况它反而没用甚至有害
批量重偏向只缓解“一写多读”式迁移场景,不是万能加速器:
- 若该 class 后续仍持续高频竞争(比如每毫秒都有多个线程抢同一组对象),JVM 会在撤销计数达 40 次后直接批量撤销整个 class 的偏向能力,锁走轻量级路径;
- 开启偏向锁本身就有微小初始化成本,纯高并发短临界区场景(如秒杀库存扣减),偏向锁从一开始就不适用;
- 在容器化环境或低延迟要求极高的服务中,部分团队会直接关闭偏向锁(
-XX:-UseBiasedLocking)以消除不确定性。
如何确认是否生效
加 JVM 参数观察日志:
-
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1:查看 safepoint 中偏向撤销相关停顿; -
-XX:+UnlockDiagnosticVMOptions -XX:+PrintBiasedLockingStatistics:输出各 class 的撤销/重偏向次数; - 配合 JOL 工具打印对象头,验证 epoch 变更与线程 ID 更新行为。


















