当前位置: 首页 > news >正文

Java synchronized 锁升级全过程深度解析:从 Mark Word 到偏向锁、轻量级锁与重量级锁的 HotSpot 实现

synchronized 是 Java 最基础也是最重要的并发原语之一。很多人以为它只是简单的互斥锁;但实际上,在 HotSpot JVM 中,synchronized 是一个拥有复杂优化策略的“锁体系”,会在运行时根据竞争情况自动进行 无锁 → 偏向锁 → 轻量级锁 → 重量级锁 的多级演进(Lock Evolution)。

现代 JVM 对 synchronized 的优化,使其性能大幅提升,甚至在低竞争情况下性能超越 ReentrantLock。

本文将从 对象头布局、CAS 操作、JVM 源码、偏向锁撤销机制、轻量级锁自旋、自适应自旋、Monitor 膨胀逻辑等维度,深度解析 synchronized 的锁升级过程及其背后的 JVM 原理。


目录

  1. 对象头(Object Header)与 Mark Word:锁状态的载体
  2. synchronized 锁的四种状态与 Mark Word 完整位图
  3. 偏向锁(Biased Locking):无竞争的极致优化
  4. 偏向锁撤销机制(安全点、Batch Revoke)
  5. 轻量级锁(Thin Lock)与 CAS 自旋原理
  6. 重量级锁(Monitor)膨胀:OS 层阻塞
  7. 锁升级全路径图(可视化)
  8. synchronized 锁升级完整源码路径解析(重点)
  9. JDK 版本下锁机制差异(8/11/17/21)
  10. 实战:如何写出对锁友好的代码
  11. 总结:JVM 锁优化的核心思想

1. 对象头:锁状态的存储中心

HotSpot 的每个对象都有对象头(Object Header),主要包含两部分:

  1. Mark Word(存储锁状态、hashcode、GC 信息、线程 ID 等)
  2. Class Pointer(指向类元数据)

Mark Word 是锁的核心载体。


2. Mark Word 在不同锁状态下的位图结构(64bit)

2.1 无锁(Normal)

unused:25 | age:4 | biased_lock:0 | lock:01

2.2 偏向锁(Biased)

threadId:54 | epoch:2 | age:4 | biased_lock:1 | lock:01

2.3 轻量级锁(Thin Lock)

ptr_to_lock_record:62 | lock:00
  • 指向线程栈中的 Lock Record

2.4 重量级锁(Monitor)

ptr_to_monitor:62 | lock:10

2.5 锁状态转换图

无锁 → 偏向锁 → 轻量级锁 → 重量级锁(不可降级)

3. 偏向锁(Biased Locking)

偏向锁是为了无竞争场景优化,让同一个线程重复加锁时不需要 CAS,自旋。

偏向锁获取流程:

  1. 检查锁标志位是否是偏向模式
  2. 检查 Mark Word 中是否记录当前线程 ID
  3. 如果是 → 直接进入同步块,不执行 CAS

偏向锁优势:
✔ 零成本加锁
✔ 高吞吐

适合:

  • 单线程环境
  • 绝大多数锁只在一个线程中使用(如 StringBuffer)

4. 偏向锁撤销(Lock Revoke)——核心高成本步骤

偏向锁的撤销是高成本的,因为:

✔ JVM 必须进入 全局安全点(Safepoint)
✔ 停顿所有线程
✔ 检查偏向锁线程的栈帧
✔ 将偏向锁转换为轻量级锁或无锁

HotSpot 关键源码(biasedLocking.cpp)

// 如果需要撤销偏向锁,要进入安全点
BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, Thread * thread) {VMThread::execute(revoke);
}

在高竞争下,偏向锁会导致大量 safepoint,反而降低性能。


5. 轻量级锁(Thin Lock):CAS + 自旋

当第二个线程试图获取偏向锁时,偏向锁会被撤销并升级到轻量级锁。

轻量级锁的设计目标:

使用 CAS + 自旋,而不是 OS 阻塞/唤醒,提高性能。

获取轻量级锁流程:

  1. 在线程栈帧创建 Lock Record
  2. 使用 CAS 将对象头指向 Lock Record
  3. CAS 成功 → 获取锁
  4. CAS 失败 → 说明竞争发生 → 自旋

6. 自旋锁(Spinlock)与自适应自旋(Adaptive Spinning)

JVM 使用自旋来等待锁释放,而不是立即进入 OS 级阻塞。

为什么自旋更快?

  • OS 阻塞/唤醒代价极高(上下文切换)
  • 轻竞争场景中,锁释放很快,自旋即可等待到

但自旋过久,会造成 CPU 浪费

因此 JVM 加入 Adaptive Spinning

  • 如果该锁在历史上自旋成功 → 增加自旋次数
  • 如果自旋失败较多 → 减少自旋次数

这是 JVM 运行时自调优的体现。


7. 重量级锁(Monitor):最终退路

当自旋失败或线程执行 wait(),JVM 会将锁升级到重量级锁。

重量级锁使用:

  • ObjectMonitor
  • OS Mutex + park/unpark 系统调用

HotSpot monitorenter 源码路径:

bytecodeInterpreter → InterpreterRuntime::monitorenter → 
ObjectSynchronizer::enter → ObjectMonitor::enter

ObjectMonitor 内使用:

for (;;) {if (TryLock()) break;Park();   // 阻塞当前线程
}

阻塞会导致:

  • 内核态切换
  • 线程上下文保存与恢复
  • 由 OS 负责调度

因此重量级锁的代价是最高的。


8. 锁升级全过程图(核心)

        无竞争↓偏向锁(无 CAS)↓(竞争)偏向锁撤销 + Safepoint↓轻量级锁(CAS + 自旋)↓(自旋失败/锁等待)重量级锁(OS 互斥量)

锁永远不会降级


9. synchronized 加锁完整源码路径解析(顶级干货)

以下是 synchronized 从字节码到 JVM 的完整流程。

9.1 字节码层

javac 会生成:

monitorenter
monitorexit

9.2 HotSpot 流程(精简)

monitorenter 执行流程(ObjectSynchronizer):
void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, TRAPS) {if (obj is unlocked)CAS to lightweight lock;else if (can inflate)inflate and acquire monitor;elseslow_enter();
}
膨胀逻辑(inflate):
ObjectMonitor* ObjectSynchronizer::inflate() {// 分配 MonitorObjectMonitor* monitor = new ObjectMonitor();// 将对象头指向 Monitorobj->mark().set_monitor(monitor);
}

自旋逻辑请参考 ObjectMonitor::EnterI()

以上是 synchronized 的底层真实执行路径。


10. JDK 版本行为变化

JDK偏向锁轻量级锁重量级锁自适应自旋
1.6默认开启支持支持支持
8默认开启支持支持完整
11默认开启支持支持完整
15默认禁用支持支持完整
17+彻底移除偏向锁支持支持完整

因此在 JDK 17+ 中锁升级路径简化为:

无锁 → 轻量级锁 → 重量级锁

但底层结构仍然相同。


11. 如何写出对 synchronized 友好的代码?

1. 避免过长的同步块

尽量缩小临界区:

synchronized(lock) {// 仅包含真正需要保护的代码
}

2. 避免锁对象频繁变化

锁对象应为 final/稳定对象。

3. 减少高竞争环境下的 synchronized

例如使用 ReentrantLock、LongAdder、ConcurrentHashMap 等更合适。


12. 总结:JVM 锁优化的核心思想

  1. 锁应该尽量无感(偏向锁)
  2. 轻竞争不陷入 OS(轻量级锁 + 自旋)
  3. 高竞争保证正确性(重量级锁)
  4. 锁只会升级,不会降级
  5. JVM 持续进行自适应优化(Adaptive heuristics)
http://www.dtcms.com/a/610786.html

相关文章:

  • 初识 Java:从“一次编写,到处运行”到核心工具链
  • Kubernetes 管理实战手册
  • ECharts 配置语法
  • 宁波市省网站建设wordpress 附件上传插件
  • 凌源网站优化网站架构包括
  • LeetCode 子矩阵元素加1
  • OpenWrt系统上配置batman-adv快速开始与配置详解
  • 西宁网站制作哪里好哪个网站做母婴用品好
  • DataWhale-HelloAgents(第四章:智能体经典范式构建)
  • C语言编译器的工作原理与使用技巧
  • 【RPA典型应用-注册及登录发布信息自动化项目】
  • ajax瀑布流网站模板西双版纳
  • 国外无版权图片网站用vs2010做网站论文
  • C++零基础通关教程第二课
  • 福建网站建建设山东省临沂建设局网站
  • 大模型应用python+Java后端+Vue前端的整合
  • Doxygen使用教程(下载链接,配置过程,语法)
  • Spring Boot Admin 踩坑
  • 企业网站广告周浦网站建设公司
  • 大模型Agent能力增强技术全景
  • 深度智能体-长短期记忆
  • dfs|bfs|定长栈|栈+双指针
  • flutter实践:DropdownButton2使用示例
  • 电商网站订烟平台官网wordpress dux1.4
  • 【信创】软硬件概览
  • 论述网站建设过程中应注意的问题电脑和手机都能浏览的网站开发
  • 扬州市住房和城乡建设网站学科分类目录
  • springboot、Mybatis-plus工程多数据源字段映射不生效
  • 大模型应用开发5-SpringAIalibaba实战
  • 网站子站怎么做的外贸网站建设的好处