目錄
1 AQS概述
AQS全稱即AbstractQueuedSynchronizer,抽象隊列同步器,提供了一套依賴隊列實現的FIFO的同步器框架,ReentrantLock,Semaphore,CyclicBarrier,CountDownLatch都是基於AQS實現的
AQS內部維護了一個volatile的state變量和一個CLH隊列,框架圖如下
2 模板方法模式
AQS定義了一組模版方法供子類覆蓋
tryAcquire(int):獨佔方式。嘗試獲取資源,成功則返回true,失敗則返回false。
tryRelease(int):獨佔方式。嘗試釋放資源,成功則返回true,失敗則返回false。
tryAcquireShared(int):共享方式。嘗試獲取資源。負數表示失敗;0表示成功,但沒有剩餘可用資源;正數表示成功,且有剩餘資源。
tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放後允許喚醒後續等待結點返回true,否則返回false。
isHeldExclusively():該線程是否正在獨佔資源。只有用到condition才需要去實現它。
2.1 獨佔方式獲取資源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
首先嚐試獲取資源,如果獲取資源失敗則將當前線程以獨佔的方式添加到執行隊列尾部
acquireQueued方法基於CAS不斷嘗試獲取資源,有興趣的同學可以看看源碼實現機制
2.2 獨佔方式釋放資源
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
如果釋放資源成功並且隊列中有正在等待的線程則通過unparkSuccessor方法喚醒其中一個waitStatus<0的線程
waitStatus有如下幾個狀態:
// 表徵等待線程已取消的
static final int CANCELLED = 1;
// 表徵需要喚醒後續線程
static final int SIGNAL = -1;
// 表徵線程正在等待觸發條件(condition)
static final int CONDITION = -2;
// 表徵下一個acquireShared應無條件傳播
static final int PROPAGATE = -3;
2.3 共享方式獲取資源
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
如果獲取成功則直接返回。如果獲取失敗則進入等待隊列,自旋的方式不斷嘗試獲取資源
tryAcquireShared方法返回結果說明:
>0:獲取資源成功,並且還有剩餘資源
=0:獲取資源成功,但是已經沒有剩餘資源
<=:獲取資源失敗
2.4 共享方式釋放資源
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
如果嘗試釋放資源成功,則進行釋放資源並且喚醒下一個線程,返回true,否則返回false
部分內容參考文章:https://www.jianshu.com/p/0f876ead2846