前言
在并發程式設計中,同步是一個重要的概念。它用于控制對共享資源的通路,確定線程之間的正确協作和資料一緻性。 Java并發包中的AbstractQueuedSynchronized(AQS)提供了一個強大的同步架構,可以用于建構各種同步器,如lock(鎖)、semaphore(信号量)、CountDownLatch(倒計時門栓)等。本文将深入探索AQS的原理和應用、特性以及AQS的源碼。
同步器是一種用于控制多線程并發通路共享資源的的機制。它確定在特定條件下隻有一個線程能夠執行關鍵代碼段或通路共享資源,以保證資料的一緻性和線程安全性。
AbstractQueuedSynchronized的原理和應用
AQS是一個抽象同步器,它基于FIFO(先進先出)等待隊列來進行管理線程的擷取和釋放。它内部維護一個同步狀态(Synchronization State)和一個等待隊列(Wait Queue)。線程在擷取同步狀态時,如果同步狀态已經被占用,則線程會被放入到等待隊列中等待。一旦同步狀态被釋放,AQS會将最先插入等待隊列中的的一個線程喚醒,使其能夠擷取同步狀态并繼續執行。
同步狀态是AQS表示同步器狀态的一個整型變量,它反映了同步器目前是否被線程占用或者是否可用。AQS通過内置的原子操作來管理同步狀态的擷取和釋放,主要包括以下方法:
- getState():擷取同步狀态的值。state == 0 代表同步狀态未被占用,staet > 0 代表同步狀态已被占用。
- setState(int newState):設定同步狀态的值。
- compareAndSetState(int expecet,int update):比較并設定同步狀态的值
AQS還提供了兩個關鍵模闆方法供子類實作:
- tryAcquire(int arg):嘗試擷取同步狀态,成功傳回true,失敗傳回false
- tryRelease(int arg):嘗試釋放同步狀态,成功傳回true,失敗傳回false
子類通過重寫這兩個方法來實作特定的同步語意。例如ReentrantLock就是基于AQS實作的可重入獨占鎖,它在tryAcquire和tryRelease方法中實作了可重入和排他性通路的邏輯。
AQS的應用十分廣泛,常見的應用場景包括:
- 鎖機制:AQS可用于建構各種類型的鎖,如獨占鎖和共享鎖。ReentrantLock和ReentrantReadWriteLock,就是基于AQS實作的常用鎖機制。
- 信号量:AQS可以用于實作信号量機制,通過控制許可數量來限制對共享資源的并發通路。Sempahore就是基于AQS實作的信号量機制、
- 倒計時門栓:AQS可以用于實作倒計時門栓機制,允許線程等待一組時間完成後再繼續執行。CountDownLatch就是基于AQS實作的倒計時門栓。
- 條件變量:AQS可以用于實作條件變量機制,允許線程在某個條件滿足時等待或繼續執行。Condition就是基于AQS實作的條件變量。
源碼詳解
java複制代碼public abstract class AbstractQueuedSynchronizer {
// 同步狀态
private volatile int state;
// 等待隊列的節點
private static final class Node {
// 線程是否共享模式
boolean isShared;
// 前驅節點
Node prev;
// 後繼節點
Node next;
// 等待狀态,表示線程等待的狀态。常見的等待狀态包括等待擷取鎖、等待被喚醒、等待條件滿足等。
int waitStatus;
// 表示與節點關聯的線程
Thread thread;
// 等待隊列中的下一個具有相同或等待狀态的節點
Node nextWaiter;
}
// 等待隊列的頭部
private transient volatile Node head;
// 等待隊列的尾部
private transient volatile Node tail;
// 擷取同步器的狀态
protected final int getState() {
return state;
}
// 設定同步器的狀态
protected final void setState(int newState) {
state = newState;
}
// 使用CAS操作設定同步器的狀态
protected final boolean compareAndSetState(int expect, int update) {
// 使用底層的原子操作來實作狀态的比較和更新
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// 省略其他方法...
}
上述示例展示了AQS的核心代碼結構,其中包含了同步狀态的定義和操作方法。AQS還定義了等待隊列的節點Node,用于管理等待擷取同步器的線程。通過調用getState(),setState(int new Staet),compareAndSetState(int expect, int update)等方法,可以對同步狀态進行讀取、修改和比較操作。
擴充
公平鎖和非公平鎖二者差別在于擷取鎖的機會是否和隊列中的順序相關,當有一個線程請求鎖時,下面是是二者分别擷取鎖的過程:
- 公平鎖:如果隊列中有線程,最先進入隊列的線程獲得鎖
- 非公平鎖:目前線程會和最先進入隊列的線程競争,競争成功擷取鎖,競争失敗放入到隊列的尾部。