synchronized加锁解锁流程

一、加锁流程

synchronized 的加锁过程涉及 锁升级机制(偏向锁 → 轻量级锁 → 重量级锁),JVM 根据竞争情况动态调整锁状态以优化性能。以下是详细步骤:


1. 无锁状态 → 偏向锁
  • 场景:首次线程访问同步块,无竞争。

  • 流程

    1. 检查对象头 :确认当前为无锁状态(锁标志位 01)。
    2. CAS 设置偏向线程 :将对象头中的 Mark Word 替换为当前线程 ID 和偏向时间戳(通过 CAS 操作)。
    3. 进入同步块:后续同一线程重入时,仅需检查线程 ID 是否匹配,无需额外操作。
  • 优点:无竞争时完全无同步开销。


2. 偏向锁 → 轻量级锁
  • 触发条件:其他线程尝试获取锁,触发偏向锁撤销。

  • 流程

    1. 暂停持有偏向锁的线程:JVM 通过安全点(Safe Point)暂停线程。

    2. 撤销偏向锁:将对象头恢复为无锁状态,并记录锁撤销信息。

    3. 升级为轻量级锁

      • 线程在栈帧中创建锁记录(Lock Record),存储对象头的 Mark Word 副本。
      • 通过 CAS 将对象头的 Mark Word 替换为指向锁记录的指针。
      • 若成功,线程获得轻量级锁;若失败,进入自旋等待。
  • 优点:竞争较小时通过 CAS 避免线程阻塞。


3. 轻量级锁 → 重量级锁
  • 触发条件:自旋超过阈值(默认 10 次)或竞争加剧。

  • 流程

    1. 膨胀为重量级锁 :JVM 创建 Monitor 对象(C++ 的 ObjectMonitor),并将对象头指向 Monitor
    2. 线程进入阻塞队列 :竞争失败的线程进入 Monitor_EntryList 队列,等待操作系统调度。
    3. 切换至内核态:依赖操作系统的互斥量(Mutex Lock)实现线程阻塞。
  • 缺点:上下文切换开销大,性能下降。


二、解锁流程

解锁过程需处理不同锁状态,并唤醒等待线程:


1. 偏向锁解锁
  • 流程

    1. 检查线程 ID:确认当前线程为锁持有者。
    2. 直接释放:无需修改对象头,保留偏向状态。
  • 特点:无竞争时解锁无开销。


2. 轻量级锁解锁
  • 流程

    1. CAS 恢复对象头 :将锁记录中的 Mark Word 副本通过 CAS 写回对象头。
    2. 成功:对象恢复为无锁状态。
    3. 失败 :说明锁已膨胀为重量级锁,唤醒 Monitor 中的等待线程。
  • 特点:依赖 CAS 操作,无线程唤醒开销。


3. 重量级锁解锁
  • 流程

    1. 释放 Monitor :将 Monitor_owner 字段置为 null
    2. 唤醒等待线程 :从 _EntryList_WaitSet 队列中唤醒一个线程。
    3. 上下文切换:操作系统调度唤醒的线程重新竞争锁。
  • 特点:涉及内核态切换,开销较大。


三、内存语义与屏障

  • 加锁时

    • Load 屏障:强制从主内存加载共享变量最新值。
    • Acquire 屏障:禁止同步块内读操作与块外指令重排序。
  • 解锁时

    • Release 屏障:强制将工作内存的修改刷新到主内存。
    • Store 屏障:禁止同步块内写操作与块外指令重排序。

四、流程图解

scss 复制代码
加锁流程:
[无锁] → (首次线程访问) → [偏向锁] → (竞争发生) → [轻量级锁] → (自旋失败) → [重量级锁]
          ↑_________________________↓               ↑_______________↓
​
解锁流程:
[偏向锁] → 无操作
[轻量级锁] → CAS 恢复对象头
[重量级锁] → 释放 Monitor,唤醒线程

五、性能优化策略

  1. 减少锁竞争

    • 缩小同步范围(如细化锁粒度)。
    • 使用无锁数据结构(如 ConcurrentHashMap)。
  2. 避免锁升级

    • 控制同步块执行时间(减少自旋失败概率)。
  3. 锁消除(Lock Elision)

    • JIT 编译器优化,去除不可能竞争的锁(如局部变量锁)。
  4. 锁粗化(Lock Coarsening)

    • 合并相邻的同步块,减少锁获取/释放次数。

六、总结

阶段 触发条件 性能开销 适用场景
偏向锁 单线程重复访问 极低 无竞争环境
轻量级锁 低并发竞争 低(CAS) 短时间同步块
重量级锁 高并发竞争 高(阻塞) 长时间同步块或高并发

关键点

  • 偏向锁轻量级锁 是 JVM 的优化手段,旨在减少无竞争或低竞争时的开销。
  • 重量级锁 是最终兜底方案,依赖操作系统实现线程阻塞与唤醒。
  • 理解锁升级流程有助于编写高效并发代码,避免不必要的性能损耗。
相关推荐
LuckyTHP21 分钟前
java 使用zxing生成条形码(可自定义文字位置、边框样式)
java·开发语言·python
无声旅者3 小时前
深度解析 IDEA 集成 Continue 插件:提升开发效率的全流程指南
java·ide·ai·intellij-idea·ai编程·continue·openapi
Ryan-Joee3 小时前
Spring Boot三层架构设计模式
java·spring boot
Hygge-star4 小时前
【数据结构】二分查找5.12
java·数据结构·程序人生·算法·学习方法
dkmilk4 小时前
Tomcat发布websocket
java·websocket·tomcat
工一木子4 小时前
【Java项目脚手架系列】第七篇:Spring Boot + Redis项目脚手架
java·spring boot·redis
哞哞不熬夜4 小时前
JavaEE--初识网络
java·网络·java-ee
等等5435 小时前
Java EE初阶——wait 和 notify
java·开发语言
API小爬虫5 小时前
淘宝按图搜索商品(拍立淘)Java 爬虫实战指南
java·爬虫·图搜索算法
lyrhhhhhhhh5 小时前
Spring 框架 JDBC 模板技术详解
java·数据库·spring