簡介
一個同步輔助類,在完成一組正在其他線程中執(zhí)行的操作之前搓蚪,它允許一個或多個線程一直等待珠十。
用給定的計數(shù) 初始化 CountDownLatch。由于調(diào)用了 countDown() 方法代承,所以在當(dāng)前計數(shù)到達零之前,await 方法會一直受阻塞渐扮。之后论悴,會釋放所有等待的線程,await 的所有后續(xù)調(diào)用都將立即返回席爽。這種現(xiàn)象只出現(xiàn)一次——計數(shù)無法被重置意荤。(如需重置,則使用CyclicBarrier)
模擬場景
給定100組初始化數(shù)據(jù)只锻,根據(jù)某個規(guī)則對這100組數(shù)據(jù)進行處理玖像,然后將結(jié)果記錄到一個數(shù)組里面。然后進行排序齐饮。
解決方案
使用for循環(huán)捐寥,循環(huán)執(zhí)行任務(wù),將結(jié)果存在list里面祖驱,再排序
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<Integer> list = new ArrayList<Integer>();
System.out.println(sdf.format(new Date()));
for (int i = 0; i < 100; i++) {
list.add(doWork(i));
}
Collections.sort(list);
System.out.println(sdf.format(new Date()));
}
public static int doWork(Integer i) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return (int) (Math.random() * 100);
}
執(zhí)行時間:
2017-08-17 13:46:41
2017-08-17 13:47:01
由于是單線程握恳,所以最后的時間是每次處理的時間之和
當(dāng)使用countDownLatch的時候,代碼:
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static List<Integer> res = new CopyOnWriteArrayList<Integer>();
private static final Integer LENGTH = 100;
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(LENGTH);
System.out.println("start at " + sdf.format(new Date()));
for (int i = 0; i < LENGTH; i++) {
Thread work = new Thread(new Worker(i, latch));
work.start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Collections.sort(res);
System.out.println("end at " + sdf.format(new Date()));
}
static class Worker implements Runnable {
int index;
CountDownLatch latch;
public Worker(int index, CountDownLatch latch) {
this.index = index;
this.latch = latch;
}
public void run() {
try {
Thread.sleep(200);
Integer i = new Random().nextInt(100);
res.add(i);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
執(zhí)行時間:
start at 2017-08-17 14:41:37
end at 2017-08-17 14:41:38
由此可見捺僻,當(dāng)我們使用countDownLatch的時候乡洼,相當(dāng)于100個任務(wù)同時啟動崇裁,然后先執(zhí)行完的等待后執(zhí)行完的結(jié)束后,我們再進行下一步的操作束昵,大大的提高了效率拔稳。
(有個小細節(jié):為什么我for循環(huán)的時候用的是ArrayList而countDownLatch用的是CopyOnWriteArrayList?線程安全)
注意的地方:
使用countDownLatch的時候锹雏,每一個任務(wù)執(zhí)行完成之后巴比,需要latch.countDown()來減少計數(shù)。因此我們需要對任務(wù)進行異常捕獲礁遵,假如任務(wù)有問題轻绞,也需要調(diào)用latch.countDown(),否則就會造成await 方法會一直受阻塞而結(jié)束不了佣耐。