锁的四种状态及升级过程

jdk1.6之前的synchronized的实现依赖于底层操作系统的互斥锁(mutex lock),这种锁被称为重量级锁,因为阻塞或唤醒一个Java线程需要操作系统切换CPU状态来实现,这种状态切换需要耗费处理器时间,如果同步代码块中内容过于简单,这种切换的赶时间可能比用户代码执行的时间还长。JDK6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。

锁的四种状态:无锁、偏向锁、轻量级锁和重量级锁,专门针对synchronized的。在1.6之前,只有重量级锁, 1.6对synchronized进行了优化,细分为四种级别的锁。

偏向锁、轻量级锁和重量级锁分别解决了三个问题:只有一个线程进入临界区,多个线程交替进入临界区,多线程同时进入临界区(自旋达到阀值,仍然无法获取到轻量级锁,线程会将此锁升级为重量级锁)。

对象头Mark Work图示如下:

偏向锁升级为轻量级锁: https://www.cnblogs.com/tiancai/p/9382542.html

线程1通过synchronized获取锁时,首先判断JVM是否支持偏向锁(默认打开),支持则尝试获取,更改“是否偏向锁”和“锁标志位”为1和01,然后CAS将线程ID更改为当前线程1,离开临界区时,线程1并不会主动释放偏向锁。线程2通过synchronized获取同一对象锁时,会优先判断对象偏向锁是否已被占用,无则进行上述操作,有则通过线程ID判断占用线程(这里1)是否已经不存在了(即线程1是否已经不需要此锁了),若不存在则先释放对象偏向锁,然后再同上述步骤,通过CAS获取偏向锁。如果线程1正在使用偏向锁,执行临界区代码,则将对象的锁升级为轻量级锁,线程1继续拥有对象锁,线程2通过自旋尝试获取锁。新来的线程3尝试获取锁时,也采用自旋的方式尝试。当某一个线程自旋次数超过JVM设定的阈值时,仍然没有获取到对象锁(轻量级锁),则将此对象锁升级为重级量,当前通过自旋尝试获取锁的线程全部进入阻塞状态,等待获取锁。注意,锁只能升级,不会降级。

猜你喜欢

转载自blog.csdn.net/qian_348840260/article/details/106477897