目录

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 的优化手段,旨在减少无竞争或低竞争时的开销。
  • 重量级锁 是最终兜底方案,依赖操作系统实现线程阻塞与唤醒。
  • 理解锁升级流程有助于编写高效并发代码,避免不必要的性能损耗。
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
nlog3n1 小时前
Java 原型模式 详解
java·开发语言·原型模式
ylfhpy2 小时前
Java面试黄金宝典30
java·数据库·算法·面试·职场和发展
喻米粒06223 小时前
RabbitMQ消息相关
java·jvm·spring boot·spring·spring cloud·sentinel·java-rabbitmq
Aphelios3805 小时前
Java全栈面试宝典:线程机制与Spring IOC容器深度解析
java·开发语言·jvm·学习·rbac
qq_529835355 小时前
装饰器模式:如何用Java打扮一个对象?
java·开发语言·装饰器模式
日暮南城故里5 小时前
Java学习------源码解析之StringBuilder
java·开发语言·学习·源码
一个public的class8 小时前
什么是 Java 泛型
java·开发语言·后端
士别三日&&当刮目相看8 小时前
JAVA学习*Object类
java·开发语言·学习
快来卷java8 小时前
MySQL篇(一):慢查询定位及索引、B树相关知识详解
java·数据结构·b树·mysql·adb
凸头9 小时前
I/O多路复用 + Reactor和Proactor + 一致性哈希
java·哈希算法