AQS
AQS(AbstractQueuedSynchronizer)
- AQS是一個用于構建鎖、同步器、協作工具類的工具類(框架)。有了AQS以后,更多的協作工具類都可以很方便得被寫出來
- ReentrantLock,Semaphore,ReentrantLock和Semaphore,包括CountDownLatch、ReentrantReadWriteLock都有這樣類似的“協作”(或者叫“同步”)功能,其實,它們底層都用了一個共同的基類這就是AQS
- 有了AQS,構建線程協作類就容易多了。
- Semaphore內部有一個Sync類,Sync類繼承了AQS

- CountDownLatch也一樣
AQS核心三部分
- state
- 這里的state的具體含義,會根據具體實現類的不同而不同比如在Semaphore里,它表示“剩余的許可證的數量”,而在CountDownLatch里,它表示“還需要倒數的數量”
- ReentrantLock中,state表示”鎖”的占有情況,包括可重入計數.值為0的時候,標識改Lock不被任何線程所占有.
- state是volatile修飾的,會被并發地修改,所以所有修改state的方法都需要保證線程安全,比如getState、setState以及compareAndSetState操作來讀取和更新這個狀態。這些方法都依賴于j.u.C.atomic包的支持
- 控制線程搶鎖和配合的FIFO隊列
- 這個隊列用來存放“等待的線程”,AQS就是“排隊管理器”當多個線程爭用同一把鎖時,必須有排隊機制將那些沒能拿到鎖的線程串在一起。當鎖釋放時,鎖管理器就會挑選-個合適的線程來占有這個剛剛釋放的鎖
- AQS會維護一個等待的線程隊列,把線程都放到這個隊列里
- 這是一個雙向形式的隊列

- 期望協作工具類去實現的獲取/釋放等重要方法
- 這里的獲取和釋放方法,是利用AQS的協作工具類里最重要的方法,是由協作類自己去實現的,并且含義各不相同
- 獲取方法
- 獲取操作會依賴state變量,經常會阻塞(比如獲取不到鎖的時候)
- 在Semaphore中,獲取就是acquire方法,作用是獲取·一個許可證
- 而在CountDownLatch里面,獲取就是await方法,作用是“等待,直到倒數結束”
- 釋放方法
- 釋放操作不會阻塞
- 在Semaphore中,釋放就是release方法,作用是釋放一個許可證
- CountDownLatch里面,獲取就是countDown方法,作用是“倒數1個數”
- 需要重寫tryAcquire和tryRelease或tryAcquireShared (int acquires)和tryReleaseShared(intreleases)等方法
AQS在CountDownLatch
- 調用CountDownLatch的await方法時,便會嘗試獲取“共享鎖”,不過一開始是獲取不到該鎖的,于是線程被阻塞。
- 而“共享鎖”可獲取到的條件,就是“鎖計數器”的值為0。
- 而“鎖計數器”的初始值為count,每當一個線程調用該CountDownLatch對象的countDown()方法時,才將“鎖計數器”-1
- count個線程調用countDown()之后,“鎖計數器”才為0,而前面提到的等待獲取共享鎖的線程才能繼續運行。
AQS在Semaphore
- 在Semaphore中,state表示許可證的剩余數量
- 看tryAcquire方法,判斷nonfairTryAcquireShared大于等于0的話,代表成功
- 這里會先檢查剩余許可證數量夠不夠這次需要的,用減法來計算,如果直接不夠,那就返回負數,表示失敗,如果夠了,就用自旋加compareAndSetState來改變state狀態,直到改變成功就返回正數;或者是期間如果被其他人修改了導致剩余數量不夠了,那也返回負數代表獲取失敗
AQS在ReentrantLock
分析釋放鎖的方法tryRelease
由于是可重入的,所以state代表重入的次數,每次釋放鎖先判斷是不是當前持有鎖的線程釋放的,如果不是就拋異常,如果是的話,重入次數就減一,如果減到了0,就說明完全釋放了,于是free就是true,并且把state設置為0。
AQS用法
第一步:寫一個類,想好協作的邏輯,實現獲取/釋放方法。
第二步:內部寫一個Sync類繼承AbstractQueuedSynchronizer
第三步:根據是否獨占來重寫tryAcquire/tryRelease或tryAcquireShared (int acquires)和tryReleaseShared(intreleases)等方法,在之前寫的獲取/釋放方法中調用AQS的acquire/release或者Shared方法
public class OneShotLatch {
private final Sync sync = new Sync();
public void signal() {
sync.releaseShared(0);
}
public void await() {
sync.acquireShared(0);
}
private class Sync extends AbstractQueuedSynchronizer {
@Override
protected int tryAcquireShared(int arg) {
return (getState() == 1) ? 1 : -1;
}
@Override
protected boolean tryReleaseShared(int arg) {
setState(1);
return true;
}
}
public static void main(String[] args) throws InterruptedException {
OneShotLatch oneShotLatch = new OneShotLatch();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"嘗試獲取latch,獲取失敗那就等待");
oneShotLatch.await();
System.out.println("開閘放行"+Thread.currentThread().getName()+"繼續運行");
}
}).start();
}
Thread.sleep(5000);
oneShotLatch.signal();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"嘗試獲取latch,獲取失敗那就等待");
oneShotLatch.await();
System.out.println("開閘放行"+Thread.currentThread().getName()+"繼續運行");
}
}).start();
}
}

浙公網安備 33010602011771號