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

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

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

Java并发编程:synchronized锁升级过程_第1张图片

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

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

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

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

Java并发编程:synchronized锁升级过程_第2张图片

2、轻量级锁(竞争小)

        加锁过程:

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

        解锁过程:

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

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

Java并发编程:synchronized锁升级过程_第3张图片

3、重量级锁

        加锁过程:

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

        解锁过程:

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

 

4、锁的对比

Java并发编程:synchronized锁升级过程_第4张图片

 

        

        

        

 

 

 

你可能感兴趣的:(java,开发语言,并发)