AQS 概述 AQS(隊列同步器,AbstractQueuedSynchronizer),是用來構建鎖或其他同步組件的核心基礎框架(比如 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch) AQS的底層結構是:一個整型變數st ...
AQS 概述
AQS(隊列同步器,AbstractQueuedSynchronizer),是用來構建鎖或其他同步組件的核心基礎框架(比如 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch)
AQS的底層結構是:一個整型變數state表示同步狀態,一個內置的FIFO隊列(同步隊列)來實現資源獲取線程的同步等待排隊,若幹個FIFO隊列(條件等待隊列)來完成持有資源線程的條件等待排隊。同步隊列如下:
AQS的使用方式
同步器的設計是基於模板方法模式的,其使用方式是繼承,子類通過繼承同步器並重寫指定的模板方法,模板方法分為3類:獨占式獲取與釋放同步狀態、共用式獲取與釋放同步狀態、查詢隊列中的等待線程。在重寫過程中可以使用同步器提供的3個方法來管理同步狀態state:getState()、setState()和compareAndSetState(),因為它們能夠保證state的改變是併發安全的。
當實現一個自定義同步組件時,推薦在內部聚合/組合一個同步器的實現類,該自定義同步組件將通過調用同步器提供的模板方法來實現自己的同步語義。為什麼不直接使用同步器呢?因為同步器自身沒有實現任何同步介面,它僅僅是定義了若幹管理同步狀態的方法,這樣有利於實現各種類型的同步組件
同步器與鎖的關係
同步器是實現鎖的關鍵,在鎖的實現中聚合/組合了一個同步器,利用該同步器實現了鎖的語義。
可以這樣理解二者之間的關係:鎖是面向使用者的,它定義了使用者與鎖的交互介面,隱藏了實現細節;而同步器面向的是鎖的實現者,它簡化了鎖的實現方式,包括屏蔽同步狀態管理、線程的排隊、等待與喚醒等底層操作。鎖和同步器很好地隔離了使用者和實現者所需關註的領域。
AQS:獲取與釋放同步狀態
1.獨占式獲取同步狀態
查看源碼 AbstractQueuedSynchronizer.acquire(..)
public final void acquire(int arg) {
//tryAcquire(..) 嘗試獲取同步狀態,由子類重寫,最經典的實現是互斥鎖:state=0(鎖自由),state>0(鎖被占用)
//acquireQueued(..) 進入同步隊列,阻塞等待獲取鎖
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
由於acquire(..)方法不響應中斷,因此AQS也提供了響應中斷、超時等待的方法:acquireInterruptibly(..)、tryAcquireNanos(..)
2.獨占式釋放同步狀態
查看源碼 AbstractQueuedSynchronizer.release(..)
public final boolean release(int arg) {
//tryAcquire(..) 嘗試釋放同步狀態,由子類重寫
if (tryRelease(arg)) {
Node h = head;
//unparkSuccessor(..) 喚醒被掛起的Node(線程)
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
3.共用式獲取同步狀態
查看源碼 AbstractQueuedSynchronizer.acquireShared(..)
public final void acquireShared(int arg) {
//tryAcquireShared(..) 嘗試獲取同步狀態,由子類重寫,最經典的實現是信號量:state>0(鎖很多),state<0(鎖不足)
//doAcquireShared(..) 進入同步隊列,阻塞等待獲取鎖
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
由於acquireShared(..)方法不響應中斷,因此AQS也提供了響應中斷、超時等待的方法:acquireSharedInterruptibly(..)、tryAcquireSharedNanos(..)
4.共用式釋放同步狀態
查看源碼 AbstractQueuedSynchronizer.
public final boolean releaseShared(int arg) {
//tryReleaseShared(..) 嘗試釋放同步狀態,由子類重寫
if (tryReleaseShared(arg)) {
//doReleaseShared(..) 喚醒被掛起的Node(線程)
doReleaseShared();
return true;
}
return false;
}
參考文章: