多線程之countDownLatch

前言
原本是昨天分享countDownLatch相關(guān)知識(shí)點(diǎn)的,但是昨天粗略看寫(xiě)了,發(fā)現(xiàn)自己對(duì)countDownLatch的認(rèn)知還不夠,所以就半道分享了常用的三種多線程線程安全解決方案的性能比較,雖然過(guò)程中翻車(chē)了,但是還是有收獲的,畢竟發(fā)現(xiàn)了自己之前的認(rèn)知問(wèn)題,也不虧。今天又去看了下count的相關(guān)知識(shí),然后做了一個(gè)小demo,感覺(jué)有點(diǎn)眉目了,所以我們來(lái)繼續(xù)看countDownLatch。
countDownLatch
countDownLath是jdk1.5引入的一個(gè)新特性,它的出現(xiàn)主要是為了解決某些應(yīng)用場(chǎng)景下多線程運(yùn)行順序的問(wèn)題。我們?cè)诙xcountDownLatch的時(shí)候,需要指定它的count大小,它就是通過(guò)這個(gè)count來(lái)控制多線程運(yùn)行順序的。
它有兩個(gè)核心的方法countDown和await,countDown的作用是當(dāng)線程執(zhí)行完后把count減一,只能用一次;await方法是判斷count是否減為0,這個(gè)方法本身是阻塞的,如果count不是0,await后面的代碼是不會(huì)被執(zhí)行的。
接下來(lái),我們通過(guò)一段示例代碼來(lái)看下countDownLatch的基本用法:
public class Example {
private static AtomicInteger count = new AtomicInteger(0);
private static final int SIZE_FIRST = 100;
private static final int SIZE_SECOND = 50;
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(SIZE_FIRST);
for (int i = 0; i < SIZE_FIRST; i++) {
executorService.execute(new Task1(countDownLatch));
}
countDownLatch.await();
final CountDownLatch countDownLatch2 = new CountDownLatch(SIZE_SECOND);
for (int i = 0; i < SIZE_SECOND; i++) {
executorService.execute(new Task2(countDownLatch2));
}
countDownLatch2.await();
for (int i = 0; i < SIZE_SECOND; i++) {
executorService.execute(new Task3());
}
executorService.shutdown();
}
static class Task1 implements Runnable {
private final CountDownLatch countDownLatch;
Task1(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("Task1: " + count.getAndIncrement());
this.countDownLatch.countDown();
}
}
static class Task2 implements Runnable {
private final CountDownLatch countDownLatch;
public Task2(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("Task2: " + count.getAndIncrement());
this.countDownLatch.countDown();
}
}
static class Task3 implements Runnable {
@Override
public void run() {
System.out.println("Task3: " + count.getAndIncrement());
}
}
}
這里我分別定義了三個(gè)線程,前兩個(gè)線程構(gòu)造的時(shí)候都需要傳入countDownLatch,然后在run方法的尾部執(zhí)行countDown方法,也就是每啟動(dòng)一個(gè)線程,count減一。
我們這里還定義了兩個(gè)countDownLatch,初始值分別是100和50,他們分別對(duì)應(yīng)線程task1和task2的執(zhí)行次數(shù)。
在線程task1和task2之間我們執(zhí)行第一個(gè)countDownLatch的await方法,控制線程task1和task2的執(zhí)行順序,確保線程task1先執(zhí)行;
在線程task2和線程task3之間我們執(zhí)行第二個(gè)countDownLatch的await方法,控制線程task2和task3的執(zhí)行順序,確保線程task2先執(zhí)行。
然后,我們運(yùn)行上面的代碼,會(huì)得到如下結(jié)果:


在以上結(jié)果中,我們可以看到,不論你執(zhí)行多少次,線程運(yùn)行順序都是task1、task2、task3,當(dāng)然await方法之前的執(zhí)行順序我們是沒(méi)有辦法控制的。
總結(jié)
從上面演示結(jié)果來(lái)看,countDownLatch主要是用來(lái)控制多線程運(yùn)行順序的,特別適合多個(gè)線程協(xié)同運(yùn)行但是有順序要求的業(yè)務(wù),更多應(yīng)用場(chǎng)景大家有時(shí)間可以好好去研究下,我們今天的內(nèi)容就到這里吧!
