深度解析:synchronized 性能演进史,从 JDK1.6 到 JDK17

摘要

synchronized 曾被认为是"重量级锁",性能不佳。但从 JDK1.6 起,经过偏向锁、轻量级锁、自适应自旋等优化,它的性能实现了质的飞跃。本文梳理了 synchronized 在 JDK1.6 到 JDK17 的演进过程,揭示性能优化背后的设计思想。


一、引言

早期 Java 开发者常常有一种刻板印象:

👉 "synchronized 很慢,要用 ReentrantLock 来替代。"

这种说法在 JDK1.5 以前的确成立,因为当时的 synchronized 直接依赖 操作系统重量级锁,用户态与内核态频繁切换,开销巨大。

但从 JDK1.6 开始,HotSpot JVM 对 synchronized 进行了深度优化,性能得到了显著提升。到 JDK17synchronized 的效率已接近甚至媲美 ReentrantLock

接下来,我们按照版本时间线来回顾 synchronized 的性能演进之路。


二、JDK1.5 之前:重量级锁的年代

在 JDK1.5 及更早版本,synchronized 几乎没有优化:

  • 直接依赖 ObjectMonitor → OS mutex
  • 线程竞争时立即进入 内核态阻塞,等待唤醒。
  • 线程切换成本极高,导致吞吐量下降。

因此,那时业界普遍推荐 java.util.concurrent.Lock 作为更优选择。


三、JDK1.6:synchronized 大规模优化的起点

JDK1.6 可以说是 synchronized 的转折点。HotSpot 引入了多种锁优化机制:

1. 偏向锁(Biased Locking)

  • 设计目标:消除无竞争场景下的锁开销
  • 实现方式:对象第一次被某线程获取锁时,Mark Word 记录该线程 ID。
  • 后续相同线程再次进入 synchronized,直接通过 Mark Word 比对即可,无需 CAS。

👉 性能提升:在单线程场景下,synchronized 的成本几乎为零。

2. 轻量级锁(Lightweight Locking)

  • 设计目标:优化短时间竞争的场景。
  • 实现方式:通过 CAS 自旋尝试获取锁,避免立即进入阻塞。
  • 如果 CAS 成功,线程直接进入临界区;失败则继续自旋一段时间。

👉 性能提升:避免频繁的内核态切换。

3. 自适应自旋锁(Adaptive Spinning)

  • 自旋次数不再固定,而是 根据历史竞争情况动态调整
  • 如果过去自旋成功率高,则延长自旋时间;否则缩短甚至直接阻塞。

👉 性能提升:减少了无意义的 CPU 消耗。

总结: JDK1.6 让 synchronized 告别了"重量级"的标签,逐渐具备了与 ReentrantLock 竞争的实力。


四、JDK1.7:偏向锁与锁粗化

JDK1.7 在 JDK1.6 的基础上进一步优化:

1. 偏向锁延迟启用

  • 在 JVM 启动初期,可能会有大量类加载、对象初始化,竞争概率较高。
  • 因此 JDK1.7 默认会延迟几秒再启用偏向锁,以避免不必要的撤销成本。

2. 锁粗化(Lock Coarsening)

  • JVM 会将 多个相邻的小同步块合并为一个大同步块
  • 目的是减少反复的加锁/解锁开销。

示例:

java 复制代码
for (int i = 0; i < 100; i++) {
    synchronized(this) {
        // do something
    }
}

在 JDK1.7 中,可能被优化为一次大的 synchronized 包裹整个循环。


五、JDK1.8:偏向锁默认开启

JDK1.8 中,偏向锁进一步普及:

  • 默认启用偏向锁,而不是延迟几秒后才启用(可以通过参数调整)。
  • 更加积极地使用偏向锁,适合大多数无锁竞争的业务场景。

同时,JVM 在锁撤销和升级的过程上也做了更高效的实现,降低了性能损耗。


六、JDK11:锁优化的稳定期

JDK11 属于 LTS 版本,许多企业的生产环境仍然在使用。

在这一阶段:

  • 偏向锁轻量级锁重量级锁 三层机制非常稳定。
  • synchronized 性能在大部分场景下已经接近 ReentrantLock。
  • 官方并未再引入新的大规模优化,而是偏向稳定性和兼容性。

七、JDK15 与 JDK17:偏向锁被移除

这是 synchronized 性能演进的又一次重大变革。

1. JEP 374:Disable Biased Locking

  • JDK15 开始,偏向锁默认被禁用。
  • JDK17,偏向锁彻底被移除。

2. 原因分析

  • 偏向锁虽然能优化无竞争场景,但在现代硬件和大多数应用场景下,实际收益有限。
  • 其实现逻辑复杂,撤销成本较高。
  • 维护偏向锁代码的收益 < 成本,因此被移除。

3. 影响

  • JDK17 之后,锁优化主要依赖 轻量级锁(CAS + 自旋)和重量级锁
  • 实际性能几乎不受影响,因为现代 JVM 和 CPU 在无锁竞争场景下的 CAS 成本已经极低。

八、性能对比与现状

我们可以粗略总结 synchronized 在不同时期的性能表现:

JDK 版本 优化手段 性能表现
JDK1.5 及之前 仅重量级锁 性能差,强依赖 OS 互斥量
JDK1.6 偏向锁、轻量级锁、自适应自旋 性能大幅提升,接近 Lock
JDK1.7 偏向锁延迟启用、锁粗化 更智能,减少无效操作
JDK1.8 偏向锁默认开启 高并发下表现更优
JDK11 三层锁机制稳定 企业主力版本,性能成熟
JDK17 移除偏向锁,轻量级锁为主 性能无明显下降,更加简洁

九、总结

  1. JDK1.5 之前:synchronized 是重量级锁,性能不佳。
  2. JDK1.6:引入偏向锁、轻量级锁、自适应自旋,性能质变。
  3. JDK1.7 - JDK8:进一步优化锁延迟、锁粗化,进入高效稳定期。
  4. JDK15 - JDK17:偏向锁被移除,但整体性能不受影响。

👉 结论:现代 synchronized 已经非常高效,在大多数业务场景下无需刻意用 ReentrantLock 替代。

相关推荐
脑子慢且灵2 小时前
【JavaWeb】一个简单的Web浏览服务程序
java·前端·后端·servlet·tomcat·web·javaee
用户298698530143 小时前
如何在 C# 中用表格替换 Word 文档中的文本?
后端
B612 little star king3 小时前
力扣29. 两数相除题解
java·算法·leetcode
野犬寒鸦3 小时前
力扣hot100:环形链表(快慢指针法)(141)
java·数据结构·算法·leetcode·面试·职场和发展
上官浩仁3 小时前
springboot synchronized 本地锁入门与实战
java·spring boot·spring
Gogo8163 小时前
java与node.js对比
java·node.js
SmartJavaAI3 小时前
Java调用Whisper和Vosk语音识别(ASR)模型,实现高效实时语音识别(附源码)
java·人工智能·whisper·语音识别
山东小木3 小时前
JBoltAI需求分析大师:基于SpringBoot的大模型智能需求文档生成解决方案
人工智能·spring boot·后端·需求分析·jboltai·javaai·aigs
用户3721574261353 小时前
Python 高效实现 Word 转 PDF:告别 Office 依赖
java