CountDownLatch是一個同步工具,它允許一個或者多個線程一直等待,直到其他線程的操作執行完成後在執行。
CountDownLatch是通過一個計數器來實作的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務後,計數器的值就會減1。當計數器的值達到0時,它表示所有的線程已經完成了任務,然後在閉鎖上等待的線程就可以恢複執行任務。
1. 源碼分析: 源碼位于rt.java 中的java.util.concurrent包中。
中文解釋: 主線程在等待所有其他的子線程執行完成後在往下執行
2、構造函數:CountDownLatch(int count)//初始化count數目的同步計數器,隻有當同步計數器為0,主線程才會向下執行
主要方法:void await()//目前線程等待計數器為0
boolean await(long timeout, TimeUnit unit)//與上面的方法不同,它加了一個時間限制。
void countDown()//計數器減1
long getCount()//擷取計數器的值
3、它的内部有一個輔助的内部類: sync
實作如下:
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = ;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == ) ? : -;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == )
return false;
int nextc = c-;
if (compareAndSetState(c, nextc))
return nextc == ;
}
}
}
4.await()方法的實作
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly();
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//調用3中的tryAcquireShared()方法
if (tryAcquireShared(arg) < )
doAcquireSharedInterruptibly(arg);//加入到等待隊列中
}
5.countDown()方法的實作
public void countDown() {
sync.releaseShared();
}
public final boolean releaseShared(int arg) {
//調用3中的tryReleaseShared()方法
if (tryReleaseShared(arg)) {
//解鎖
doReleaseShared();
return true;
}
return false;
}
應用場景:
比如主任務是一個比較複雜的運算,為了節約時間,我們可以拆分為多個子任務,多線程同時執行,最終統一彙總任務。
其實生活也有類似的場景,比如馬拉松賽跑,我們不可能按順序依次跑步,這樣得跑到猴年馬月。一般來說都是大家聽到發号指令一起跑,最終比賽結束,統一彙總成績。
代碼案列:
下面看一個例子大家就清楚CountDownLatch的用法了:
/**
* CountDownLatch,一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待
* 構造方法參數指定了計數的次數
* countDown方法,目前線程結束執行後調用,計數減一
* awaint方法,調用此方法會一直阻塞目前線程,直到計時器的值為0
* 建立時間 2017年8月15日
*
*/
public class CountDownLatchDemo {
final static SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
final static String startTime = sdf.format(new Date());
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch();// 兩個賽跑者
Runer runer1 = new Runer("劉翔", , latch);
Runer runer2 = new Runer("羅伯斯", , latch);
runer1.start();//劉翔 開始跑步
runer2.start();//羅伯斯 開始跑步
latch.await();// 等待所有人賽跑結束
System.out.println("all runer done at " + sdf.format(new Date()));
}
static class Runer extends Thread {
String runerName;
int runTime;
CountDownLatch latch;
public Runer(String runerName, int runTime, CountDownLatch latch) {
this.runerName = runerName;
this.runTime = runTime;
this.latch = latch;
}
public void run() {
System.out.println("Runer " + runerName + " do run begin at "
+ startTime);
doRun();//跑步
System.out.println("Runer " + runerName + " do run complete at "
+ sdf.format(new Date()));
latch.countDown();// 終點結束,計數器減一
}
private void doRun() {
try {
Thread.sleep(runTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}