jdk 6 之后,jvm 对 synchronized 进行了重量级锁优化,引入了偏向锁和轻量级锁机制,使得在大多数无竞争场景下无需进入操作系统内核态进行阻塞,从而显著降低了同步开销。具体做法是:jvm 会根据竞争的激烈程度自动升级锁的状态,从偏向锁(无竞争)到轻量级锁(自旋竞争),最后才升级为重量级锁(阻塞等待)。

synchronized 的锁升级过程是怎样的
锁升级是一个单向不可逆的过程,旨在减少获取和释放锁的系统调用成本。在无多线程竞争时,对象头中的 Mark Word 会记录当前线程 ID,实现偏向;当出现竞争时,通过 CAS 操作尝试将锁登记在当前线程栈帧中,实现轻量级;若竞争激烈或自旋失败,则膨胀为指向互斥量对象的指针,即重量级锁。

public class LockUpgradeDemo {
public static void main(String[] args) {
Object obj = new Object();
// 模拟偏向锁阶段
synchronized (obj) {
System.out.println("First thread acquired lock");
}
// 模拟轻量级锁阶段(需配合 -XX:+UseBiasedLocking=false 等参数观察不同行为,此处仅展示结构)
new Thread(() -> {
synchronized (obj) {
System.out.println("Second thread tries to acquire");
}
}).start();
}
}
运行上述代码,在默认 JDK 8 环境下,首次获取锁时会触发偏向锁设置。若开启偏向锁撤销,后续竞争可能直接升级为轻量级或重量级锁。实际输出取决于 JVM 启动参数及系统负载。
如何验证锁是否发生了升级
可以通过使用 jcmd 工具查看堆内存中特定对象的元数据来验证锁状态。需要指定目标进程 ID 和类名,并启用 -XX:+PrintAssembly 或结合 jstat 分析 GC 日志间接推断,但最直接的是使用 jcmd 配合 jmap dump 后分析,或者使用 Arthas 的 monitor 命令监控方法执行耗时变化。

// 假设使用 Arthas 监控
monitor -c 5 com.example.LockUpgradeDemo main
// 观察 CPU 消耗和锁等待时间
watch com.example.LockUpgradeDemo main '{returnObj,throwExp}' -x 2
在实际操作中,更推荐直接使用 jcmd 查看线程栈,若看到 parking to wait for 且伴随 ObjectMonitor,说明已处于重量级锁状态。若未出现此类阻塞,且方法执行极快,则可能停留在轻量级或偏向锁阶段。
偏向锁撤销的条件是什么
偏向锁的撤销发生在其他线程尝试获取该锁时。此时 JVM 会检查 Mark Word 中的线程 ID 是否与当前请求线程一致,若不一致,则通过 CAS 操作尝试将偏向状态撤销,并根据情况升级为轻量级锁或直接膨胀为重量级锁。此外,JVM 全局安全点也会触发偏向锁的批量撤销。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











