我的原則:先會用再說,內部慢慢來。
學以致用,根據場景學源碼
一、概念
- CountDownLatch 理解爲:手動倒計時。(輸入一個整數,然後每次-1,直到state = 0,退出)
也叫做閉鎖,在完成某些運算是,只有其他所有線程的運算全部完成,當前運算才繼續執行。
可以用於計算數量,平均值,等待線程退出等等等等。
二、主要方法
- CountDownLatch#countDown 遞減1
- CountDownLatch#await() 共享鎖阻塞等待 state = 0
三、源碼分析
爲了便於理解,建議先讀一下我的另一篇文章,介紹AQS 【線程】ReentrantLock 源碼剖析 (八)
3.1 整體架構
package java.util.concurrent;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class CountDownLatch {
// 繼承 AQS 的Sync
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) { //初始化設置狀態,也就是鎖的個數
setState(count);
}
int getCount() { //獲取鎖數量
return getState();
}
protected int tryAcquireShared(int acquires) { //嘗試進行加鎖 ,getState() == 0表示當前空閒,沒人佔據鎖,我可以拿到
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) { //嘗試釋放鎖,這個 releases參數沒鳥用
// Decrement count; signal when transition to zero
for (;;) {
int c = getState(); //獲取狀態
if (c == 0) //是0的話,說明沒有鎖了,那麼就釋放失敗,返回 false
return false;
int nextc = c-1; //每次釋放 1
if (compareAndSetState(c, nextc)) //CAS 設置狀態,不成功就for自旋,必須設置成功爲止
return nextc == 0;
}
}
}
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); } //等待條件滿足被喚醒
public boolean await(long timeout, TimeUnit unit) //等待條件滿足被喚醒 (條件加了個超市)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() { sync.releaseShared(1); } // -1操作,拿掉一個鎖
public long getCount() { return sync.getCount(); } // 獲取鎖數量
public String toString() { return super.toString() + "[Count = " + sync.getCount() + "]"; }
}
3.2 CountDownLatch 初始化
final CountDownLatch latch = new CountDownLatch(2);
- 看下構造方法 CountDownLatch(int count)
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
...
private volatile int state; // 當前持有鎖的數量,0表示沒人持有鎖
protected final void setState(int newState) {
state = newState;
}
...
}
初始化的目的就是:套N個鎖上去,然後一個個拿掉。
3.3 await 剖析
java.util.concurrent.CountDownLatch#sync
- await 方法
public void CountDownLatch#await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
- acquireSharedInterruptibly 方法
public final void AbstractQueuedSynchronizer#acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException(); // 被打斷就直接拋異常了
if (tryAcquireShared(arg) < 0) // -1 沒拿到鎖,1 拿到了鎖。
doAcquireSharedInterruptibly(arg); // 拿到鎖才進入這個方法
}
- tryAcquireShared 方法
protected int Sync#tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; // -1 沒拿到鎖,1 拿到了鎖。
}