JDK 6 对 synchronized 优化后引入偏向锁,分析其在无竞争环境中的性能提升原因?

2026-04-30 11:562阅读0评论SEO资源
  • 内容介绍
  • 相关推荐

本文共计681个文字,预计阅读时间需要3分钟。

JDK 6 对 synchronized 优化后引入偏向锁,分析其在无竞争环境中的性能提升原因?

它解决的根本问题不是并发控制,而是消除无竞争时的+CAS操作。在JDK 6之前,只有1个线程反覆调用synchronized方法,每次进入都要执行一次CAS去更新对象的Mark Word——看似轻量,但原子指令仍涉及内存屏障、缓存行刷新等隐含的隐秘性。偏向锁简化为一次内存读(比较线程ID),直接进入临界区,零同步原语。

触发偏向锁的三个硬性前提缺一不可

  • JVM 启动参数未禁用:默认开启(-XX:+UseBiasedLocking),但 JDK 15+ 默认关闭,需显式加该参数
  • 对象未计算过 hashCode:一旦调用 Object.hashCode()System.identityHashCode(),对象头必须腾出空间存哈希值,会强制撤销偏向状态
  • 未过 JVM 启动延迟期:默认前 4 秒内新建对象不启用偏向(-XX:BiasedLockingStartupDelay=0 可关掉)

性能收益只在特定模式下明显,且容易被误判

典型高收益场景:synchronized 修饰的 getter/setter、递归调用的同步方法、单线程循环中频繁加锁的计数器。实测显示,在纯单线程、百万次调用下,偏向锁比轻量级锁快 10%–20%,主要省在避免了 100 万次 CAS。

但以下情况反而拖慢:

  • 多个线程交替访问同一对象:每次新线程来都会触发偏向撤销(revoke),代价远高于直接走轻量级锁
  • 对象被大量用于 HashMap 的 key:隐式调用 hashCode,立刻退化为无锁状态
  • 使用了 wait()/notify():JVM 会直接升级为重量级锁,偏向锁失效

查证偏向锁是否生效,不能只看代码写法

运行时状态得靠工具确认,比如用 jmap -histo:live 配合 -XX:+PrintSafepointStatistics 观察锁撤销次数,或用 JOL(Java Object Layout)打印对象头:new Object() 在偏向启用后,Mark Word 应含非零 thread_id 字段;若看到 lock=01 & biased_lock=0,说明已被禁用或撤销。

真正容易被忽略的是:偏向锁的收益高度依赖“访问模式稳定性”。一旦业务逻辑引入任意一个 hashCode 调用或跨线程共享,整个优化链就断了——它不像轻量级锁那样有自适应兜底,而是直接降级,且不可逆。

本文共计681个文字,预计阅读时间需要3分钟。

JDK 6 对 synchronized 优化后引入偏向锁,分析其在无竞争环境中的性能提升原因?

它解决的根本问题不是并发控制,而是消除无竞争时的+CAS操作。在JDK 6之前,只有1个线程反覆调用synchronized方法,每次进入都要执行一次CAS去更新对象的Mark Word——看似轻量,但原子指令仍涉及内存屏障、缓存行刷新等隐含的隐秘性。偏向锁简化为一次内存读(比较线程ID),直接进入临界区,零同步原语。

触发偏向锁的三个硬性前提缺一不可

  • JVM 启动参数未禁用:默认开启(-XX:+UseBiasedLocking),但 JDK 15+ 默认关闭,需显式加该参数
  • 对象未计算过 hashCode:一旦调用 Object.hashCode()System.identityHashCode(),对象头必须腾出空间存哈希值,会强制撤销偏向状态
  • 未过 JVM 启动延迟期:默认前 4 秒内新建对象不启用偏向(-XX:BiasedLockingStartupDelay=0 可关掉)

性能收益只在特定模式下明显,且容易被误判

典型高收益场景:synchronized 修饰的 getter/setter、递归调用的同步方法、单线程循环中频繁加锁的计数器。实测显示,在纯单线程、百万次调用下,偏向锁比轻量级锁快 10%–20%,主要省在避免了 100 万次 CAS。

但以下情况反而拖慢:

  • 多个线程交替访问同一对象:每次新线程来都会触发偏向撤销(revoke),代价远高于直接走轻量级锁
  • 对象被大量用于 HashMap 的 key:隐式调用 hashCode,立刻退化为无锁状态
  • 使用了 wait()/notify():JVM 会直接升级为重量级锁,偏向锁失效

查证偏向锁是否生效,不能只看代码写法

运行时状态得靠工具确认,比如用 jmap -histo:live 配合 -XX:+PrintSafepointStatistics 观察锁撤销次数,或用 JOL(Java Object Layout)打印对象头:new Object() 在偏向启用后,Mark Word 应含非零 thread_id 字段;若看到 lock=01 & biased_lock=0,说明已被禁用或撤销。

真正容易被忽略的是:偏向锁的收益高度依赖“访问模式稳定性”。一旦业务逻辑引入任意一个 hashCode 调用或跨线程共享,整个优化链就断了——它不像轻量级锁那样有自适应兜底,而是直接降级,且不可逆。