批量重偏向是JVM自动启用的优化机制,需同时满足:同类型对象、已被T1偏向锁定、T2无竞争访问;当同类对象连续20个被T2尝试获取且T1已不活跃时,第21个起直接改偏向线程ID,避免CAS和锁记录开销。

偏向锁批量重偏向机制不是靠手动“触发”的,而是 JVM 在检测到特定竞争模式后自动启用的优化策略。它真正起作用的前提是:**大量同类型对象被同一类线程反复访问,随后被另一类线程交替访问,且整体无真实竞争**。只有满足这个场景,批量重偏向才能避免逐个撤销+升级的开销,显著降低锁膨胀带来的性能损耗。
批量重偏向生效的三个硬性条件
缺一不可,否则 JVM 会走常规轻量级锁升级路径:
-
对象属于同一个类:JVM 按类维度统计,40 个
A实例可以,但混入B实例就会中断统计 - 前一批对象已被线程 T1 偏向锁定:T1 必须完成对这批对象的首次同步访问,使它们进入“已偏向 T1”状态
-
T2 访问同一批对象时未发生并发竞争:T2 是在 T1 完全退出后才开始访问(如用
t1.join()保证),且访问节奏不重叠
关键阈值与默认行为
JVM 内部设有一个计数器,当发现某类对象中连续出现20 个以上被 T2 尝试获取但原偏向线程(T1)已不活跃的情况时,就判定为“批量重偏向候选”。此时:
- 前 20 个对象仍按常规流程升级为轻量级锁(CAS 修改 Mark Word)
- 第 21 个及之后的对象,JVM 直接将它们的偏向线程 ID 改写为 T2,并重置 epoch —— 这步无需 CAS,仅一次内存写入
- 该类后续新创建的对象,默认也偏向 T2,直到下一次批量重偏向发生
为什么它能提升性能
核心在于减少了两类昂贵操作:
立即学习“Java免费学习笔记(深入)”;
- 避免大量 CAS 失败重试:单个对象从偏向锁升级为轻量级锁需 CAS 修改 Mark Word;200 个对象就是 200 次 CAS,失败率高、缓存行失效频繁
- 跳过轻量级锁的栈帧锁记录分配:轻量级锁要在每个线程栈中新建 Lock Record;批量重偏向后,T2 后续访问这些对象直接走偏向路径,零额外内存开销
实际开发中怎么配合它
你不能强制调用“开启批量重偏向”,但可以设计代码让它更容易命中:
- 避免在循环里 new 不同类的锁对象(比如
new Object()放在 for 里),保持锁对象类型集中 - 对缓存池、对象池类结构,让同一线程先初始化一批实例,再由另一批工作线程统一处理
- 不主动禁用偏向锁(如启动参数
-XX:-UseBiasedLocking),JDK 15+ 默认仍启用(部分云环境可能关闭,需确认) - 用 JOL 工具打印
ClassLayout.parseInstance(obj).toPrintable()观察 Mark Word 变化,验证是否真进入了批量重偏向路径



















