Java并发编程之锁膨胀

(图片出自黑马程序员)

一、锁膨胀的触发条件

  1. 多线程竞争:当多个线程尝试获取同一个对象的锁。
  2. 自旋失败:竞争线程在轻量级锁阶段通过自旋(循环重试)尝试获取锁失败,达到阈值(如自旋次数超过JVM动态调整的阈值)。

二、轻量级锁 → Monitor锁的详细过程

1. 初始状态(轻量级锁)
  • 场景:单线程或低并发环境下,线程通过CAS操作将对象头的Mark Word替换为指向线程栈中锁记录的指针。
  • 对象头标记Mark Word标记为轻量级锁状态(标志位 00)。
  • 特点:无需操作系统介入,性能开销低。

java对象头:
图片出自黑马程序员
Mark Word结构:

2. 竞争发生
  • 线程B尝试获取锁:当另一个线程(线程1)尝试通过CAS获取锁时,发现对象头中的指针已被线程0占用。
    在这里插入图片描述

  • 自旋尝试:线程1进入自旋状态(循环重试),等待线程0释放锁。

3. 自旋失败,触发锁膨胀
  • 自旋超限:若线程1自旋一定次数后仍未获取锁(默认策略或适应性自旋策略判断失败),JVM判定为高竞争场景。
  • 锁膨胀流程
    1. 分配Monitor对象:JVM为当前对象创建一个ObjectMonitor(Monitor锁的核心结构)。

    2. 修改对象头:将对象头的Mark Word替换为指向ObjectMonitor的指针,标志位变为重量级锁(10)。
      在这里插入图片描述

    3. 线程状态变更

      • 线程0继续执行同步代码,但锁的管理移交至ObjectMonitor
      • 线程1被挂起(进入阻塞状态),加入ObjectMonitor的等待队列(EntryList)。
4. Monitor锁的运行机制
  • ObjectMonitor结构
    • owner:指向持有锁的线程。
    • EntryList:阻塞等待锁的线程队列。
    • WaitSet:调用wait()方法的线程队列。
  • 锁竞争失败后的行为
    • 线程竞争锁失败后直接进入阻塞状态(通过操作系统互斥量实现),不再自旋
    • 锁释放后,JVM从EntryList中唤醒线程重新竞争。

三、总结

  1. 锁膨胀不可逆:一旦升级为重量级锁,不会降级(除非对象被回收后重新创建)。
  2. 性能权衡
    • 轻量级锁:低开销(CAS + 自旋),适合低竞争场景。
    • Monitor锁:高开销(涉及操作系统内核态切换),但避免CPU空转,适合高竞争场景。
  3. 适应性自旋优化:JDK 6后JVM根据历史竞争情况动态调整自旋次数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值