偏向锁在无竞争时避免同步开销,但发生多线程竞争时,jvm自动触发撤销并升级为轻量级或重量级锁;撤销需在safepoint暂停线程,检查偏向线程状态后清理mark word,支持批量撤销与重偏向优化。

偏向锁在无竞争时避免同步开销,但一旦发生多线程竞争,JVM 会通过偏向锁撤销(Revoke)触发锁升级,动态转为轻量级锁或重量级锁。这个过程不是由用户控制,而是由 JVM 在运行时根据对象头标记和线程状态自动完成。
偏向锁撤销的触发时机
当一个已偏向某线程的对象被其他线程尝试获取锁时,JVM 检测到竞争,就会启动撤销流程。注意:不是每次进入 synchronized 都检查,而是在发现当前线程不是偏向线程且对象仍处于偏向状态时才触发。
- 该对象的 Mark Word 中偏向标志位为 1,且偏向线程 ID 不为空
- 请求锁的线程与 Mark Word 中记录的偏向线程 ID 不一致
- 此时 JVM 不会直接阻塞,而是先尝试安全地撤销偏向锁
撤销过程的关键步骤
撤销不是“立刻清除”,而是分阶段、需保证安全性的操作:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 全局安全点(Safepoint)等待:JVM 必须暂停所有 Java 线程,确保目标线程不正在执行同步块(否则无法修改其栈帧中的锁记录)
- 检查偏向线程是否存活:若偏向线程仍存活且未退出同步块,需将其栈中相关锁记录(Lock Record)恢复为未锁定状态
- 将 Mark Word 清空偏向信息:设置为“匿名偏向”或直接升级为轻量级锁(取决于是否已有锁记录)
- 若此时有多个线程争抢,可能直接膨胀为重量级锁(ObjectMonitor)
撤销失败与批量重偏向
频繁撤销会带来性能损耗,JVM 提供了优化机制:
- 批量撤销(Bulk Revoke):当某个类的实例在一定时间内被撤销超过阈值(默认 20 次),JVM 会为该类禁用偏向锁,新实例直接走轻量级锁路径
- 批量重偏向(Bulk Rebias):若检测到某类对象从线程 A 偏向转向线程 B 的模式稳定,可跳过撤销,直接将 Mark Word 中的线程 ID 替换为 B(无需进入 Safepoint)
- 这些策略由 JVM 自动启用,可通过 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 控制启动时机
如何观察和验证撤销行为
可通过 JVM 参数输出锁状态变化:
- -XX:+PrintGCDetails -XX:+PrintSafepointStatistics 查看 Safepoint 停顿(撤销必经)
- -XX:+UnlockDiagnosticVMOptions -XX:+PrintBiasedLockingStatistics 输出偏向锁统计(如撤销次数、批量操作等)
- 使用 JOL(Java Object Layout)工具查看对象头 Mark Word 变化,确认偏向位、线程 ID、epoch 等字段是否更新
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










