没有锁竞争时,synchronized 一定是偏向锁吗?

43 阅读1分钟

结论:不一定。

在没有锁竞争时,synchronized 锁默认会首先尝试升级为偏向锁,但并非在所有情况下都一定是偏向锁,存在一些例外场景会阻止偏向锁的启用。

核心原理

Java 的锁优化采用“锁膨胀”机制,在无竞争时会优先选择开销最小的锁状态:

1.初始状态:对象创建后,锁状态为“无锁”。

2.首次加锁:当线程第一次获取 synchronized 锁时,JVM 会将对象头的锁标志位设为“偏向锁”,并记录当前持有锁的线程 ID(避免 CAS 操作,进一步降低开销)。

阻止偏向锁启用的关键场景

即使没有锁竞争,以下情况也会导致 synchronized 直接使用轻量级锁而非偏向锁:

偏向锁延迟启用:JVM 默认会延迟几秒钟(如 4 秒)才开启偏向锁(可通过 JVM 参数 -XX:BiasedLockingStartupDelay=0 取消延迟)。在延迟期间,首次加锁会直接使用轻量级锁。

禁用偏向锁:若通过 JVM 参数 -XX:-UseBiasedLocking 显式禁用了偏向锁功能,所有无竞争的 synchronized 都会使用轻量级锁。

类已发生偏向锁撤销:如果某个类的对象曾经历过“偏向锁→轻量级锁”的膨胀(如曾有竞争),JVM 可能会标记该类为“不可偏向”,后续该类的新对象即使无竞争,加锁时也会直接使用轻量级锁。

线程执行了 wait()/notify():调用这两个方法会强制锁膨胀为重量级锁,后续即使无竞争,也无法回到偏向锁状态。