概念
CountDownLatch是一個(gè)同步工具類(lèi)澜公,用來(lái)協(xié)調(diào)多個(gè)線(xiàn)程之間的同步,或者說(shuō)起到線(xiàn)程之間的通信(而不是用作互斥的作用)锦爵。
CountDownLatch能夠使一個(gè)線(xiàn)程在等待另外一些線(xiàn)程完成各自工作之后垄分,再繼續(xù)執(zhí)行影锈。使用一個(gè)計(jì)數(shù)器進(jìn)行實(shí)現(xiàn)延曙。計(jì)數(shù)器初始值為線(xiàn)程的數(shù)量豌鹤。當(dāng)每一個(gè)線(xiàn)程完成自己任務(wù)后,計(jì)數(shù)器的值就會(huì)減一枝缔。當(dāng)計(jì)數(shù)器的值為0時(shí)布疙,表示所有的線(xiàn)程都已經(jīng)完成了任務(wù),然后在CountDownLatch上等待的線(xiàn)程就可以恢復(fù)執(zhí)行任務(wù)愿卸。
用法一
某一線(xiàn)程在開(kāi)始運(yùn)行前等待n個(gè)線(xiàn)程執(zhí)行完畢灵临。將CountDownLatch的計(jì)數(shù)器初始化為n new CountDownLatch(n) ,每當(dāng)一個(gè)任務(wù)線(xiàn)程執(zhí)行完畢趴荸,就將計(jì)數(shù)器減1 countdownlatch.countDown()儒溉,當(dāng)計(jì)數(shù)器的值變?yōu)?時(shí),在CountDownLatch上 await() 的線(xiàn)程就會(huì)被喚醒发钝。一個(gè)典型應(yīng)用場(chǎng)景就是啟動(dòng)一個(gè)服務(wù)時(shí)顿涣,主線(xiàn)程需要等待多個(gè)組件加載完畢,之后再繼續(xù)執(zhí)行酝豪。
用法二
實(shí)現(xiàn)多個(gè)線(xiàn)程開(kāi)始執(zhí)行任務(wù)的最大并行性涛碑。注意是并行性,不是并發(fā)孵淘,強(qiáng)調(diào)的是多個(gè)線(xiàn)程在某一時(shí)刻同時(shí)開(kāi)始執(zhí)行蒲障。類(lèi)似于賽跑,將多個(gè)線(xiàn)程放到起點(diǎn)瘫证,等待發(fā)令槍響揉阎,然后同時(shí)開(kāi)跑。做法是初始化一個(gè)共享的CountDownLatch(1)痛悯,將其計(jì)數(shù)器初始化為1余黎,多個(gè)線(xiàn)程在開(kāi)始執(zhí)行任務(wù)前首先 coundownlatch.await(),當(dāng)主線(xiàn)程調(diào)用 countDown() 時(shí)载萌,計(jì)數(shù)器變?yōu)?惧财,多個(gè)線(xiàn)程同時(shí)被喚醒。
不足
CountDownLatch是一次性的扭仁,計(jì)數(shù)器的值只能在構(gòu)造方法中初始化一次垮衷,之后沒(méi)有任何機(jī)制再次對(duì)其設(shè)置值,當(dāng)CountDownLatch使用完畢后乖坠,它不能再次被使用搀突。
部分代碼
先看看構(gòu)造函數(shù),其只有一個(gè)構(gòu)造函數(shù)
public CountDownLatch(int count) { }; //參數(shù)count為計(jì)數(shù)值
而下面這3個(gè)函數(shù)就是其最重要的操作函數(shù)
public void await() throws InterruptedException { };
//調(diào)用await()方法的線(xiàn)程會(huì)被掛起熊泵,它會(huì)等待直到count值為0才繼續(xù)執(zhí)行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//和await()類(lèi)似仰迁,只不過(guò)等待一定的時(shí)間后count值還沒(méi)變?yōu)?的話(huà)就會(huì)繼續(xù)執(zhí)行
public void countDown() { };
//將count值減1
示例
import java.util.concurrent.CountDownLatch;
public class Main {
public static final CountDownLatch latch = new CountDownLatch(2);
public static class tmp implements Runnable{
@Override
public void run() {
try {
System.out.println("子線(xiàn)程"+Thread.currentThread().getId()+"正在執(zhí)行");
Thread.sleep(300);
System.out.println("子線(xiàn)程"+Thread.currentThread().getId()+"執(zhí)行結(jié)束");
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Thread(new tmp()).start();
new Thread(new tmp()).start();
try {
System.out.println("等待2個(gè)線(xiàn)程執(zhí)行");
latch.await();
System.out.println("2個(gè)線(xiàn)程執(zhí)行完畢");
System.out.println("主線(xiàn)程執(zhí)行完畢");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
輸出結(jié)果為:
等待2個(gè)線(xiàn)程執(zhí)行
子線(xiàn)程9正在執(zhí)行
子線(xiàn)程10正在執(zhí)行
子線(xiàn)程10執(zhí)行結(jié)束
子線(xiàn)程9執(zhí)行結(jié)束
2個(gè)線(xiàn)程執(zhí)行完畢
主線(xiàn)程執(zhí)行完畢