说说Java的AbstractQueuedSynchronizer

天NULL / 2024-01-24 / 原文

Java中的Lock锁,都是基于AQS,也就是AbstractQueuedSynchronizer。那么AbstractQueuedSynchronizer又是基于什么原理来做锁的呢?

一:锁原理

1.  怎么算获取到了锁?

AQS内置了一个volatile int state字段,利用CAS保证并发安全,当state=0表示没没有线程占用。只要线程设置了state(比如置为1,如果

是可重入锁,state可以>1),就表示获取了锁。

 

2. 线程竞争时如何保存竞争的线程?

AQS内置了一个双链表,当线程存在竞争时,会先放入这个双链表的尾部。当然,这个放入的动作,也要保证并发安全,这里也是使用了

CAS原子操作,死循环执行这个放入动作直至成功。

 

3. 竞争线程保存后如何获取锁?

AQS做的很简单,直接死循环尝试获取锁直至成功。具体思路为:

3.1   取当前线程所属节点的上一个节点A。

3.2   如果节点A为头结点,则当前线程尝试获取锁。

3.3   没有获取到锁,则循环3.1 、 3.2

3.4   当获取到锁后,将当前节点置为头结点。这样,排在后边的节点,就会开始获取锁。

之所以要先判断上一个节点为头结点才尝试获取锁,主要有两个原因:

一:CAS操作相对于单纯的判断更加吃CPU。

二:这样保证了获取锁的公平性,方便公平锁的实现。

 

4.  锁释放

各种不同类型的锁,锁释放思路不同。但是都要刷 state=state-1。

 

 

二:AQS的优点

可以实现语义更加丰富的锁,比如读写锁、公平锁、非公平锁。