1 AQS 簡介
- AQS 爲抽象鎖隊列,它內部引入了一個鎖隊列,並實現了獲取鎖隊列失敗後線程的入隊列操作和成功釋放鎖後,喚醒隊列下一個節點線程的出隊列操作
- AQS 也提供了獲取和釋放鎖的模板,子類只要實現獲取/釋放鎖(tryAcquire/tryRelease)的邏輯,就可以實現一個完成的鎖,如 ReentrantLock、ReentrantReadWriteLock
- AQS、ReentrantLock、ReentrantReadWriteLock 結構與源碼分析 一文中 分析了AQS 的結構
2 Semaphore 簡介
- 需求分析:一個旅遊景區,當人數達到額定值時,就不能在放入進去了,出來一個人才能進去一個人
- 概要設計:AQS 正好可以實現上面的需求
- 可將 state 變量設爲額定值(state 表示剩餘的可獲取的資源)
- 當一個線程獲取鎖成功後,將 state - 1。釋放鎖成功後,將 state + 1
- 當 state < = 0 時,表示沒有資源了,獲取資源的線程將被掛起
2.1 Semaphore 設計
- 以下即是最簡潔的 Semaphore 所需要的核心代碼,自己實現的僅僅只有 tryAcquireShared()、tryReleaseShared()。其餘的部分都被 AQS 實現了,可見 AQS 的強大。
public class MySemaphore {
private Sync sync;
public MySemaphore(int permits) {
this.sync = new Sync(permits);
}
public void acquire() {sync.acquireShared(1);}
public void release() {sync.releaseShared(1);}
static class Sync extends AbstractQueuedSynchronizer {
private int max;
public Sync(int permits) {
setState(permits);
max = permits;
}
@Override
protected int tryAcquireShared(int arg) {
int state;
for (;;) {
if ((state = getState()) - arg < 0) return -1;
if (compareAndSetState(state,state-arg)){
return 1;
}
}
}
@Override
protected boolean tryReleaseShared(int arg) {
for(;;) {
int state = getState();
int nextS = state + arg;
if (nextS > max) {
throw new Error("acquire 和 release 的個數不相同!");
}
if (compareAndSetState(state,nextS)) {
return true;
}
}
}
}
}
3 CountDownLatch 簡介
- 需求分析:某場考試,只有所有考生都來了之後,監考老師才能髮捲子(真實情況不可能哦)
- 概要設計:同樣可以用 AQS 來實現
- 可將額定值設爲 state 變量(state 的值表示有多少把鎖還沒有被釋放)
- 某個考試入場,則釋放一把鎖(state - 1),如果 state == 0 時,才喚醒所有等待鎖的線程(監考老師)
- 並且獲取鎖成功的條件是 state <= 0
3.1 CountDownLatch 設計
- 同樣最簡潔的 CountDownLatch 所需要的核心代碼,也僅僅實現了 tryAcquireShared() 和 tryReleaseShared() 方法,就將我們需要的功能實現了,可見 AQS 的強大
public class MyCountDownLatch {
private Sync sync;
public MyCountDownLatch(int count){sync = new Sync(count);}
public void countDown(){sync.releaseShared(1);}
public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}
static class Sync extends AbstractQueuedSynchronizer {
public Sync(int count) {setState(count);}
@Override
protected int tryAcquireShared(int arg) {return getState() <= 0 ? 1 : -1;}
@Override
protected boolean tryReleaseShared(int arg) {
for(;;) {
int state = getState();
if (state <= 0) return false;
int nextS = state - arg;
if (compareAndSetState(state,nextS)) {
return nextS <= 0;
}
}
}
}
}
4 總結
- 我們只需通過重寫 AQS 中的 獲取鎖、釋放鎖方法,就可以實現各種功能的鎖!
- 並且 AQS 已經爲我們提供了中斷鎖、tryLock() 的全部代碼。我們僅僅需要實現普通鎖,就可以直接得到另外兩把鎖!