偏向锁在高版本java中被默认禁用,因其依赖的单线程长期持锁假设已不成立;多核高并发导致频繁撤销触发stw、短命对象使初始化成本超收益、内存与cpu开销增加,故转向更稳健的轻量级锁路径。

偏向锁在高版本 Java 中被默认禁用,核心不是它“做错了”,而是它原本依赖的运行假设——单线程长期持有锁——在现代系统中已不成立。它从轻量优化变成了隐性负担。
多核高并发让“偏向”失去前提
偏向锁的设计基于一个经验观察:多数对象在生命周期内只被一个线程反复访问。但如今服务器普遍是 32 核、64 核起步,微服务请求由不同线程池分发,一个 HTTP 请求里创建的 Request 对象可能刚被线程 A 偏向,几十毫秒内就被线程 B、C 轮番争抢。此时“偏向”不仅没省开销,反而触发频繁撤销,成了性能瓶颈。
撤销过程强制全局停顿(STW)
只要第二个线程尝试获取已被偏向的锁,JVM 就必须执行撤销流程:
- 暂停所有 Java 线程,等待它们到达 safepoint
- 遍历目标线程栈,定位并修复锁记录
- CAS 更新对象头 Mark Word,转为轻量级锁状态
这个过程无法局部化,一次撤销就可能拉高整个应用的 P99 延迟,在高 QPS 场景下尤为明显。
短命对象泛滥,初始化成本反超收益
WebFlux、Spring WebMvc 等框架大量创建短暂存活的对象(如封装类、DTO),很多对象生命周期远小于默认 4 秒的偏向延时。刚被偏向就回收,线程 ID 写入、epoch 维护、撤销判断等初始化成本,完全抵消甚至超过所谓“零开销重入”的收益。
内存与 CPU 开销持续走高
偏向锁不是免费的:
- 每个对象头需额外预留空间存 threadID 和 epoch,64 位 JVM 下占满 62 位,增加 GC 压力
- 每次新建对象都要判断是否启用、是否可偏向、是否在延时期,条件跳转干扰 CPU 流水线
- 撤销路径比轻量级锁失败时的单次 CAS 更复杂、更重
实测显示,在典型 API 场景中开启偏向锁后,GC 日志频繁出现 Revoking bias of objects 记录,说明撤销已是常态而非例外。
转向更稳健的轻量级锁路径
禁用偏向锁不等于放弃优化,而是资源投向更普适的路径:
- 无锁 → 轻量级锁(CAS + 自旋)→ 重量级锁
- UseAdaptiveSpinning 启用后,JVM 可根据前次自旋成功率动态调优次数
- 轻量级锁升级为重量级锁前,仍可通过 ObjectMonitor 队列公平排队,不依赖全局 safepoint
这套路径在多核、高并发、短生命周期对象为主的现代应用中,稳定性与吞吐表现更优。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











