JDK 15 默认禁用偏向锁(-XX:+UseBiasedLocking
)的原因
1. 偏向锁的设计目标与局限性
偏向锁(Biased Locking)是 JVM 为减少无竞争同步操作开销而设计的优化机制。其核心思想是:当一个锁对象首次被某一线程获取后,JVM 会将该线程 ID 记录在锁对象的标记字段中,后续该线程无需再执行 CAS 操作即可快速获取锁。
- 适用场景:单线程重复获取锁(如单例初始化、无竞争循环)。
- 问题场景:
- 当多个线程实际竞争锁时,偏向锁需执行撤销(Revocation)操作,将其升级为轻量级锁或重量级锁。
- 撤销操作会触发全局安全点(Safepoint),可能导致线程暂停(STW),增加延迟抖动。
- 在高并发、短生命周期的锁对象场景中,偏向锁的维护成本可能超过其性能收益。
2. 现代硬件与应用场景的演变
- 多核处理器普及:现代服务器普遍具备数十核的硬件环境,锁竞争频率显著增加。偏向锁的撤销操作在高并发场景中频繁触发,反而成为性能瓶颈。
- 锁优化技术多样化:
- JVM 引入了更高效的同步机制(如自旋锁优化、适应性自旋、锁消除、锁粗化)。
- 轻量级锁(Thin Lock)和重量级锁(Heavyweight Lock)的升级策略已足够成熟,无需依赖偏向锁的中间优化层。
- 短期对象增多:微服务、函数计算等场景中,大量短期对象(如 HTTP 请求上下文)的锁竞争更倾向轻量级锁,而非偏向锁。
3. 官方性能分析与决策依据
- 基准测试结果:
- Oracle 官方测试显示,在多数现代应用中,禁用偏向锁后:
- 吞吐量无显著下降:尤其在高度竞争场景下,轻量级锁的直接使用减少了撤销开销。
- 延迟稳定性提升:避免了因全局安全点导致的延迟尖峰。
- 例如,在 SPECjbb2015 测试中,禁用偏向锁后 99% 的延迟波动降低 5%-10%。
- Oracle 官方测试显示,在多数现代应用中,禁用偏向锁后:
- 维护成本与代码简化:
- 偏向锁的实现逻辑复杂,占用了 JVM 约 2% 的代码量,维护难度高。
- 弃用偏向锁可减少 JVM 潜在 Bug 风险(如撤销逻辑的竞态条件)。
4. 开发者应对建议
- 无需主动干预:
- 大多数应用升级到 JDK 15+ 后,默认禁用偏向锁不会导致性能劣化,JVM 的轻量级锁优化已足够高效。
- 特殊情况处理:
- 若应用依赖偏向锁(如遗留单线程高频锁场景),可通过 JVM 参数
-XX:+UseBiasedLocking
重新启用,但需谨慎评估长期兼容性风险。
- 若应用依赖偏向锁(如遗留单线程高频锁场景),可通过 JVM 参数
- 代码优化方向:
- 减少同步块粒度(如使用
ConcurrentHashMap
替代synchronized
块)。 - 优先使用无锁数据结构(如
AtomicInteger
)或线程封闭(如ThreadLocal
)。
- 减少同步块粒度(如使用
总结
JDK 15 默认禁用偏向锁,是 JVM 团队基于现代硬件特性、应用场景变化及性能实测数据的综合决策。这一调整简化了 JVM 内部实现,同时推动开发者采用更适应高并发环境的同步策略。对于绝大多数应用,无需额外配置即可平滑过渡。