Java并发编程:synchronized锁升级过程

        锁的状态有四种,级别从高到低分别为:无锁状态偏向锁状态轻量级锁状态重量级锁状态,这个锁的状态会随着并发激烈情况逐渐升级,锁的状态升级但不能降级。引入这些状态时为了减少获得锁和释放锁带来的性能消耗。

        对象锁的状态是存在对象头的Mark Word中的。

f0afceab15274bec85e8f51e01144eb3.png

1、偏向锁状态(无竞争、或竞争很少)

        经过研究表明,大多数情况下,锁不仅不存在多线程竞争,而且大多数都是由同一个线程多次获得,这种情况下如果没有线程和线程A竞争锁,但线程A每次获取锁都要修改对象头,指向线程A,那么太过消耗资源。而偏向锁所做的就是再对象头和栈帧中的锁记录中存锁偏向的线程ID,等以后该线程进入和退出同步块是都不需要进行CAS操作进行加锁和解锁,只需要检查以下对象头中的Mark Word中释放有指向线程A的偏向锁

偏向锁使用的是一种只有出现竞争才释放锁的机制

        当一个线程B想要获取这个对象锁,那么他要先看看这个的是否为偏向锁的标志位是否为0,如果为0直接将其变为指向线程B的偏向锁就好,如果为1则先暂停线程B,然后检查线程A是否还处于活动状态,如果线程A已经不处于活动状态了,则将对象头设为无锁状态,然后线程B则尝试使用CAS将其指向指向自己。如果还活着,要么会将对象头的Mark Word偏向线程A,要么回复到无锁状态或者标志这个对象不适合作为偏向锁(要进行升级)。此时会唤醒线程B继续获取锁。

2289160a11054e648dcc4d2fc4552e8f.png

2、轻量级锁(竞争小)

        加锁过程:

        线程获取锁的过程:再当前线程的栈帧中创建用于储存锁记录的空间,并将对象头中的MarkWord复制到锁记录当中,然后会通过CAS将对象头中的Mark Word替换为指向锁记录的指针,如果成功,则当前线程获得锁,如果失败,则说明此时有其他线程再竞争这个锁,当前线程此时会自旋CAS的方式来获取锁(类似于while循环的方式不断尝试去获取锁,直到原持有锁的线程释放锁,当前线程获得锁)。

        解锁过程:

        轻量级锁不同于偏向锁,等执行完同步代码块,则会进行解锁。解锁过程:会使用CAS操作将锁记录中的Mark Word替换回对象头,如果成功,则说明没有发生竞争。如果失败,则说明再当前线程占用锁的过程中,有其他线程竞争这个锁,将其替换为重量级锁了,则无法CAS进行替换。

        当长时间CAS自旋都无法获取锁(一定次数),则这个线程会将这个锁从轻量级锁升级到重量级锁。这样子是为了方式自旋的无用功,浪费CPU资源。锁变为重量级锁了,当前线程也进入了阻塞状态。

6d051eba33614e1b8635b0680da56aa5.png

3、重量级锁

        加锁过程:

        重量级锁的加锁过程和轻量级锁差不多,但就是如果尝试获取锁失败的话,并不会自旋获取锁,而是直接阻塞,等待这个锁释放。

        解锁过程:

        重量级锁的解锁过程再解锁的时候,也差不都,会将Mark Word替换回来,然后将阻塞再这个锁上的线程给唤醒,让它们争夺这个锁。

 

4、锁的对比

3aff125118204912b73291881eb07707.png

 

        

        

        

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

日上三杆快起床

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

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

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

打赏作者

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

抵扣说明:

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

余额充值