簡介
CountDownLatch,一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。
源碼分析
CountDownLatch的實現方式是在內部定義了一個實現AbstractQueuedSynchronizer(詳見:JUC 源碼分析 - AbstractQueuedSynchronizer(AQS))的內部類Sync,Sync主要實現了AbstractQueuedSynchronizer中共享模式的獲取和釋放方法tryAcquireShared和tryReleaseShared,在CountDownLatch中使用AQS的子類Sync,初始化的state表示一個計數器,每次countDown的時候計數器會減少1,直到減爲0的時候或超時或中斷,await方法從等待中返回。
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) {//await方法會調用,當前計數器爲0是才返回,不爲0時,會掛起當前線程,直到計數器減少爲0的時候,才被countDown方法依次喚醒
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {//countDown方法會調用,每次調用都會使計數器減1,直到減少爲0的時候,會返回true,依次喚醒等待中的線程,使從await方法返回。
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
public void await() throws InterruptedException {//該方法等待計數器減少爲0,await系列方法分別調用AQS的共享模式的acquire系列方法
sync.acquireSharedInterruptibly(1);
}
public void countDown() {//該方法減少計數器,調用AQS的共享模式的release方法
sync.releaseShared(1);
}
使用方式
主線程等待子線程都執行完任務後才返回。
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch c = new CountDownLatch(3);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.countDown();
System.out.println("countDown 1000 : " + c.getCount());
}
});
thread.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.countDown();
System.out.println("countDown 2000 : " + c.getCount());
}
});
thread2.start();
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
c.countDown();
System.out.println("countDown 3000 : " + c.getCount());
}
});
thread3.start();
System.out.println("await before : " + c.getCount());
c.await();
System.out.println("await after : " + c.getCount());
}
}