偏向锁在JDK 15起默认禁用,因其多核高并发下收益为负:撤销触发STW、内存开销大、短命对象使初始化成本超收益,而轻量级锁+自旋已更优。

偏向锁在 JDK 15 及之后版本默认被禁用,不是因为设计错误,而是硬件演进和应用模式变化让它的收益彻底逆转——它从“优化”变成了“拖累”。
多核高并发让“单线程长期持有”假设彻底失效
偏向锁的根基是:一个对象大概率只被同一个线程反复访问。但现代服务器普遍是 32 核、64 核起步,微服务请求由不同线程池分发,synchronized 锁住的对象常在几十毫秒内就被多个线程轮番争抢。此时“偏向”某个线程不仅没省开销,反而触发频繁撤销,成了性能瓶颈。
撤销过程强制全局 safepoint,直接拉高延迟毛刺
只要第二个线程尝试获取已被偏向的锁,JVM 就必须执行 biased_lock_revocation:
- 暂停所有 Java 线程(STW),等它们到达 safepoint
- 遍历目标线程栈,定位并修复锁记录
- CAS 更新对象头 Mark Word,转为轻量级锁状态
这个过程无法局部化,一次撤销就可能卡住整个应用的响应时间,在高 QPS 场景下显著恶化 P99 延迟。
立即学习“Java免费学习笔记(深入)”;
短生命周期对象泛滥,初始化成本远超收益
Spring WebFlux、Quarkus、函数计算等框架大量创建毫秒级存活的对象(如 RequestWrapper、Context 实例)。而 JVM 默认偏向锁延时是 4 秒(-XX:BiasedLockingStartupDelay=4000),对象刚被标记为偏向,还没来得及被第二次访问,就被 GC 回收了。每次创建对象还要判断是否可偏向、是否在延时期——这些分支预测本身就在消耗 CPU 流水线。
内存与维护开销持续走高,性价比归零
每个对象头需额外预留空间存 threadID 和 epoch(64 位 JVM 下达 62 位),加剧内存压力和 GC 负担;撤销路径复杂度远高于轻量级锁的单次 CAS;实测中典型 HTTP API 场景下,GC 日志频繁出现 Revoking bias of objects 记录,说明撤销已成常态而非例外。JVM 团队选择把资源投向更稳健的路径:无锁 → 轻量级锁(CAS + 自适应自旋)→ 重量级锁,这条路径不依赖全局停顿,适配多核真实负载。


















