AQS概述
AQS 是JUC并發(fā)包中ReentrantLock,ReentrantReadWriteLock,CountDownLatch,CyclicBarrier等類的底層實現(xiàn)。
AQS主要是維護了一個CLH阻塞隊列(雙向隊列)

image.png
這個隊列中保存的是沒有獲得鎖的線程。
獲取鎖資源
線程A
ReentrantLock lock = new ReentrantLock(true);
Condition condition = lock.newCondition();
try{
lock.lock();
//.....
condition.await();
}finally{
lock.unlock();
}
具體過程如下:
- 1.有A,B兩個線程去獲取資源,A線程通過Lock方法獲取鎖資源。
- 2.B線程接著去調(diào)用Lock方法想獲取已經(jīng)屬于A的鎖資源。
- 3.B線程會因為獲取鎖失敗(通過CAS操作對狀態(tài)位進行標記來獲取鎖),被封裝成Node節(jié)點放入到AQS CLH雙向隊列中
- 4.調(diào)用LockSupport.park()將線程阻塞掛起。
- 5.同理其他再想爭用線程A鎖的線程也會被加入CLH隊列中,并被掛起。
condition
我們知道Lock和synchronized的一大區(qū)別就是Lock支持條件的,Lock和condition的關系是1:n的,即一個lock可以有多個條件
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();

image.png
條件阻塞
Lock和使用condition步驟如下:
- 1.線程A需要通過lock方法先獲得lock鎖。
- 2.當線程A調(diào)用到condition.await()釋放鎖(通過CAS操作對狀態(tài)進行標記)
- 3.阻塞線程A
- 4.線程A封裝成node節(jié)點放入條件隊列中(每個條件有自己的條件隊列,和AQS的CLH隊列無關)
- 5.由于資源被釋放,因此去AQS中喚起一個之前被阻塞掛起的線程。
條件釋放
try
{
lock.lock();
...
condition.signal();
}
finally
{
lock.unlock();
}
- 1.已經(jīng)有線程A因為lock的條件被加入到條件隊列,并且被掛起(但是不會將線程加入AQS阻塞隊列,因為條件尚未滿足)。同時線程A釋放lock鎖
- 2.線程B獲取lock鎖
- 3.線程B之行condition.signal將原本已經(jīng)因為條件不滿足加入到條件隊列的線程B取出。并將線程B加入到AQS阻塞隊列中
- 4.當線程B之行unlock操作,阻塞隊列中的線程A可以進行l(wèi)ock的資源爭搶。
AQS概述已經(jīng)講完了,下篇介紹下AQS源碼層面相關。