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 的优化手段,旨在减少无竞争或低竞争时的开销。
  • 重量级锁 是最终兜底方案,依赖操作系统实现线程阻塞与唤醒。
  • 理解锁升级流程有助于编写高效并发代码,避免不必要的性能损耗。
相关推荐
AI多Agent协作实战派6 分钟前
AI多Agent协作系统实战(四十六):改了十次规则,AI员工还是老样子——会话缓存的坑
java·spring·缓存
一知半解仙17 分钟前
当机器人学会泛化,而我在写Java:一名后端开发者的2026年8月21日观察手记
java·开发语言·机器人
葡萄成熟时 !9 小时前
JAVA 常用API学习笔记
java·笔记·学习
Rain的Java大神之路10 小时前
介绍一下分布式事务
java·分布式·后端·spring·spring cloud·架构·springcloud
吴声子夜歌10 小时前
Java面试题——基础(一)
java·开发语言
南城以南溫暖如初14711 小时前
外卖CPS实战指南:从技术选型到运营落地全流程解析
java·spring boot·mysql·架构·vue
傻啦嘿哟11 小时前
英雄联盟皮肤爬虫:爬取全皮肤价格与特效,做比价工具
java·c++·爬虫
码匠许师傅12 小时前
【C++ 面试真题】24. 聊聊 C++ 的时间日期处理
java·c++·面试
mqiqe13 小时前
AgentScope Java 2.0 Agent 状态存储(AgentStateStore)深度解析:构建可恢复、可扩展的智能体运行时
java·运维·网络
zhifou12345613 小时前
java 17升级安装
java·开发语言