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 的优化手段,旨在减少无竞争或低竞争时的开销。
  • 重量级锁 是最终兜底方案,依赖操作系统实现线程阻塞与唤醒。
  • 理解锁升级流程有助于编写高效并发代码,避免不必要的性能损耗。
相关推荐
小阳拱白菜35 分钟前
java异常学习
java
FrankYoou2 小时前
Jenkins 与 GitLab CI/CD 的核心对比
java·docker
麦兜*2 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
KK溜了溜了2 小时前
JAVA-springboot 整合Redis
java·spring boot·redis
天河归来3 小时前
使用idea创建springboot单体项目
java·spring boot·intellij-idea
weixin_478689763 小时前
十大排序算法汇总
java·算法·排序算法
码荼3 小时前
学习开发之hashmap
java·python·学习·哈希算法·个人开发·小白学开发·不花钱不花时间crud
IT_10243 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
ye904 小时前
银河麒麟V10服务器版 + openGuass + JDK +Tomcat
java·开发语言·tomcat
武昌库里写JAVA4 小时前
Oracle如何使用序列 Oracle序列使用教程
java·开发语言·spring boot·学习·课程设计