Synchronized的升级过程

锁的升级过程

Java中锁的升级可以分为:

无锁--->偏向锁--->轻量级锁--->重量级锁

偏向锁:

当锁对象第一次被线程获取进入偏向状态,标记为101,同时CAS,将线程ID记录到MarkWord中,如果CAS成功,这个线程以后进入自己的同步块查看这个ID是自己表示没有竞争,无需任何操作。

一个对象创建时:

  • 如果开启了偏向锁,对象创建后MarkWord值为0x05,即最后3位为101.thread、epoch、age都为0。

  • 偏向锁是默认延迟的,不会在程序启动时立即启动。

  • 当一个对象已经计算过hashCode,就再也无法进入偏向状态了。

  • 添加VM参数 --XX:-UseBiasedLocking 禁用偏向锁。

撤销偏向状态:

  1. 调用对象的hashCode:偏向锁的markword记录的是线程的ID,调用hashCode导致偏向锁被撤销。

  2. 当有其他线程使用偏向锁对象时,会将偏向锁升级为轻量级锁。

  3. 调用wait/notify 需要申请Monitor,进入waitSet

轻量级锁

多个线程竞争同一个锁的时候,JVM会将锁从偏向锁升级到轻量级锁。在轻量级锁中Markword中记录了指向锁记录的指针。

线程获取轻量级锁,会使用CAS操作,将MarkWord替换成指向自己的锁记录的指针,如果CAS成功,则说明获取轻量级锁成功,可以进入同步块,如果CAS失败,则表示锁竞争失败,需要升级为重量级锁。

具体流程
  1. 创建锁记录(Lock Record) 对象,每个线程的栈帧都会包含一个锁记录的结构,存储锁定对象的MarkWord。

  2. 让所记录中的Object reference指向被锁住的对象,并尝试用CAS替换Object的Mark Word,将Mark Word的值替换,存入锁记录。

    1. 如果CAS成功,对象头中存储了锁记录地址和状态00(轻量级锁),表示由该线程给对象加锁。

    2. 如果CAS失败:

      1. 如果其他线程已经持有了该Object的轻量级锁,这时表明有竞争,进入锁膨胀过程。

      2. 如果是线程自己执行了synchronized锁重入,就添加一条Lock Record作为重入的计数

  1. 当退出synchronized代码块(解锁):

    1. 如果有取值为null的锁记录,表示重入,这时重置锁记录,表示重入计数-1。

    2. 如果锁记录不为null,这时使用CAS,将MarkWord的值恢复给对象头

      1. 成功,则解锁成功。

      2. 失败,则说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程。

重量级锁

Thread-1加锁失败,进入锁膨胀阶段,为Object对象申请Monitor锁,通过object对象头获取到持有锁的线程,将该线程设置为owner,将对象头的markword设置为指向monitor的地址。然后自己进入Monitor的EntryList BLOCKED.

当Thread-0退出代码块解锁:

使用CAS将MarkWord的值恢复给对象头失败,进入重量级锁的解锁流程。即按照Monitor找到Monitor,将owner设置为null,唤醒EntryList中的BLOCKEd线程。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五敷有你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值