偏向锁未失效,而是撤销代价过高导致stw开销远超轻量级锁的cas总和;biasedlockingbulkrebiasthreshold=20和bulkrevokethreshold=40分别表示同一class对象被撤销20次后批量重偏向、40次后彻底禁用偏向锁。

偏向锁在现代多核 JVM 中不是“失效了”,而是它的撤销代价已经高到无法承受——一次撤销就触发 STW,而这种 STW 在高并发服务里比轻量级锁的几十次 CAS 还贵。
为什么 BiasedLockingBulkRebiasThreshold=20 和 BiasedLockingBulkRevokeThreshold=40 是关键阈值
这两个参数不是随意定的,它们直接对应 JVM 对“某个 class 下对象是否还值得偏向”的成本判断:
-
BiasedLockingBulkRebiasThreshold=20:同一 class 的对象被撤销 20 次后,JVM 认为“这把锁不该再认旧主了”,于是批量重偏向——只更新 epoch,不改线程 ID,避免下一轮再进安全点 -
BiasedLockingBulkRevokeThreshold=40:再翻一倍,JVM 彻底放弃,对该 class 所有新对象禁用偏向锁,后续新建对象直接走轻量级锁路径 - 注意:统计单位是 class,不是单个对象;
synchronized(obj)触发撤销,但synchronized(obj.getClass())才真正计入这个 class 的计数器
撤销操作必须等 Safepoint 的真实影响
撤销不是“立刻执行”的原子操作,它必须等所有 Java 线程都跑到一个 Safepoint,才能安全修改对象头。这意味着:
- 哪怕只是 1 个对象被另一个线程竞争,也会导致整个 JVM 暂停(STW),哪怕其他线程根本没碰这个锁
- 在吞吐密集型服务(如网关、连接池)中,频繁的
synchronized块 + 多线程轮询访问,会让偏向锁变成 STW 发射器 - 现代 CPU 上,几十次
CAS的开销远小于一次 STW —— 尤其当 STW 持续 0.5ms 以上时,已足以打乱 GC 或响应 SLA
JDK 15+ 默认关闭 -XX:-UseBiasedLocking 不是“淘汰”,而是收益归零
这不是技术过时,而是硬件与使用模式变了:
- 单核时代:偏向锁省掉的每次 CAS 都是实打实的性能提升
- 多核高并发时代:锁还没偏 3 次就被争抢,撤销成本反超轻量级锁自旋总和
- JDK 15 起默认禁用,JDK 20 彻底移除,说明 JVM 团队已将优化重心完全转向
adaptive spinning和更激进的锁消除(Lock Elimination) - 如果你还在 JDK 8 上调优,
-XX:-UseBiasedLocking可能比保留它更快;但别指望靠调高阈值“抢救”——只要存在跨线程访问 pattern,撤销就注定发生
真正容易被忽略的点是:偏向锁的“成本”不在加锁,而在撤销;而撤销不是由你写的代码触发的,是由 JVM 在安全点统一调度的——你无法预测它何时发生,也无法控制它影响范围。这才是现代同步优化绕不开的硬约束。










