CountDownLatch
CountDownLatch是一個(gè)同步器, 允許一個(gè)或多個(gè)線程執(zhí)行完畢,再繼續(xù)執(zhí)行, 可以用來協(xié)調(diào)多個(gè)線程的同步。
CountDownLatch通過計(jì)數(shù)器實(shí)現(xiàn), 計(jì)數(shù)器的初始值是線程的數(shù)量, 每當(dāng)一個(gè)線程執(zhí)行完畢, 計(jì)數(shù)器減1, 當(dāng)計(jì)數(shù)器減為0或達(dá)到超時(shí)時(shí)間時(shí), 等待的線程開始恢復(fù)執(zhí)行。
應(yīng)用場景
某一個(gè)線程等待n個(gè)線程執(zhí)行完畢, CountDownLatch初始化為CountDownLatch(n), 當(dāng)某個(gè)任務(wù)線程執(zhí)行執(zhí)行結(jié)束時(shí),調(diào)用countDown方法,計(jì)數(shù)器減1, 當(dāng)計(jì)數(shù)器減為0時(shí), 表示n個(gè)任務(wù)線程全部執(zhí)行完畢,await的線程被喚醒, 開始執(zhí)行。典型場景為,主線程等待所有子任務(wù)結(jié)束,繼續(xù)下一步。 比如服務(wù)啟動(dòng)時(shí)等待多個(gè)組件加載完畢,啟動(dòng)服務(wù)。
多個(gè)線程等待某個(gè)線程執(zhí)行結(jié)束, 開始并發(fā)執(zhí)行, CountDownLatch初始化為CountDownLatch(1), 每個(gè)等待線程啟動(dòng)時(shí)調(diào)用該CountDownLatch await方法被阻塞, 當(dāng)主線程執(zhí)行完成, 計(jì)數(shù)器減1, 同時(shí)喚醒多個(gè)等待線程開始執(zhí)行。
重要方法
// 構(gòu)造器
public CountDownLatch(int count) {}
//
public void await() throws InterruptedException {}
//
public boolean await(long timeout, TimeUnit unit) throws InterruptedException{}
//
public void countDown() {}
- 構(gòu)造器
CountDownLatch的構(gòu)造器僅有一個(gè)int參數(shù), 代表阻塞的線程數(shù)量。 - await
調(diào)用此方法的線程會(huì)被掛起, 直到count值降為0才會(huì)被喚醒。 - await(long timeout, TimeUnit unit)
調(diào)用此方法的線程會(huì)被掛起, 直到count值降為0或超時(shí)才會(huì)被喚醒。 - countDown
調(diào)用此方法, count值減1
示例
- 主線程等待n個(gè)線程執(zhí)行結(jié)束
final CountDownLatch countDownLatch = new CountDownLatch(10);
for(int i=0; i<10; i++){
final int finalI = i;
Runnable thread = new Runnable() {
@Override
public void run() {
System.out.println(finalI);
countDownLatch.countDown();
}
};
thread.run();
}
countDownLatch.await();
- 并發(fā)執(zhí)行
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(1);
final CountDownLatch countDownLatch1 = new CountDownLatch(10);
final int[] a = {0};
for(int i=0; i<10; i++){
Runnable thread = new Runnable() {
@Override
public void run() {
try {
System.out.println(a[0]);
countDownLatch.await();
a[0] += 1;
countDownLatch1.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
service.execute(thread);
}
countDownLatch.countDown();
countDownLatch1.await();
System.out.println(a[0]);
原理解析
TODO AQS