Java偏向锁\轻量级锁\重量级锁总结

 

资源消耗

目的

场景

实现方式

偏向锁

一个线程只有一次CAS

单线程进行同步块时,消除轻量级锁的CAS操作。

大多数场景为单线程访问同步块,一旦有竞争,偏向锁失效。

判断markword是否指现当前线程

轻量级锁

每次进出同步块,都要进行CAS设置Mark word,出现锁竞争时,自旋获得锁,不进行用户态与内核态切换。

以自旋与CAS操作的方式进行线程同步,减少线程态切换带来的性能问题

追求相应时间;

同步块执行很快时,一旦超过自旋阈值,则升级为重量级锁

判断markword是否指现当前线程的 lock record

重量级锁

每次进出同步块,都要进行CAS设置Mark word,出现锁竞争时,线程阻塞挂起,进行用户态与内核态切换。

线程同步

追求吞吐量;

同步块执行时间长

判断markword是否指现锁对像。

偏向锁

Java偏向锁旨在对于无并发争用的前提下,进行真正意义上的无锁同步。个人理解就是线程在获取锁之前先检查是否偏向,偏向了就直接拿对象头中存储的线程ID与当前线程做比较,如果一致就继续执行,不一致就撤销偏向,走无偏向锁定流程。

关于这里面的撤销偏向,是通知已经获取偏向锁的线程撤销(也就是对象头记录的线程ID),还是争用偏向锁的线程(即当前线程)撤销呢?撤销的具体过程又是什么样的呢?

1、偏向锁升级:一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它。

hash

age

是否偏向锁:1

锁标识位:01

2、所以当第一个线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头MarkWord成为偏向锁的时候使用CAS操作,并将对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。

线程ID

epoch

age

是否偏向锁:1

锁标识位:01

3、一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程。

设置成无锁状态。????无锁状态是下面的哪种????

hash

Age

是否偏向锁:1

锁标识位:01

null

epoch

age

是否偏向锁:1

锁标识位:01

重新偏向线程2

线程2ID

age

是否偏向锁:1

锁标识位:01

4、如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁(偏向锁就是这个时候升级为轻量级锁的)。

先标记为非偏向模式

Hash

age

是否偏向锁:0

锁标识位:01

再进行轻量级锁升级

Lock record 地址

锁标识位:00

此后对象再也回不到偏向锁模式

5、如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。

设置成无锁状态。????无锁状态是下面的哪种????

hash

Age

是否偏向锁:1

锁标识位:01

null

epoch

age

是否偏向锁:1

锁标识位:01

猜你喜欢

转载自blog.csdn.net/tony820418/article/details/78084732