JVM优化下synchronized锁机制

文章详细阐述了Java对象在synchronized同步块中的锁状态,包括无锁、偏向锁、轻量级锁和重量级锁,并重点解析了锁升级的具体过程。从MarkWord在对象头中的表示,到线程申请锁时的判断逻辑,再到偏向锁的撤销和轻量级锁的获取,都进行了详尽的介绍,特别是锁升级涉及的CAS操作和状态转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在看synchronized底层实现的八股的时候,发现对JVM底层优化的思路,大多数博客只是基本介绍了无锁,偏向锁,轻量锁和重量锁四种锁状态,并没有看到详细给出锁升级的步骤的文章,部分文章也只是描述了一个锁升级成另一个锁的部分,并没有完整的串起来。因此自己参考多篇文章的思路整理了一下整个转换的过程。

申请锁的步骤

首先,了解一下不同锁状态在对象头的Mark Word中对应的结构。
在这里插入图片描述

在任何情况下,对象一定处于这四种状态中的一种(也有可能状态位为11,用于GC,不能再被获取,所以此处不讨论),那么在线程访问synchronized修饰的代码时,首先就会读取Mark Word中的内容,查看当前的锁状态。

  • 若锁状态位为10,则执行重量级锁的MonitorEnter和MonitorExit命令来进行加锁/解锁。
  • 若锁状态位为00,则当前有线程持有该对象的轻量级锁,那么申请锁的线程需要自旋等待,若等待成功,则获得锁,若等待失败,则将轻量级锁升级为重量级锁。
  • 若锁的状态位为01,则此时对象的状态是无锁或者偏向锁,下面使用流程图来说明具体的过程。
    在这里插入图片描述
  1. 判断是否允许偏向锁以及是否存在偏向锁
    • 若不支持偏向锁,则直接获取轻量锁
    • 若无偏向锁则使用CAS获取偏向锁
    • 若偏向锁是自己的则可以直接运行代码
    • 否则,存在别的线程占用偏向锁(假设占用锁的线程为A,当前线程为B),需要进行偏向锁的撤销
      1. 等待线程A进入全局安全点
      2. 暂停线程A,判断A是否在执行当前锁区域代码
        • 若是,则发生锁冲突,将偏向锁升级为轻量锁,由线程A去申请该轻量锁,线程B自旋等待轻量锁
        • 若不是,则未发生冲突,线程B使用CAS去获取偏向锁
  2. 申请轻量锁的步骤
    1. 在线程的栈中开辟一个Record Lock的空间
    2. 将Mark Word的内容拷贝到Record Lock中
    3. 使用CAS修改Mark Word中的内容:
      1. 将Mark Word前62位替换为指向自己线程栈中的Record Lock的指针
      2. 将Mark Word最后2位的锁状态位改为00
  3. 若申请轻量锁时,CAS失败,则将轻量锁升级为重量锁;若成功,则执行代码,并在退出时,使用CAS将Record Lock中的内容拷贝回Mark Word,并修改状态位。若此时轻量锁已经被升级重量级锁,则唤醒锁等待的线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值