CountDownLatch是在java1.5被引入的,跟它一塊兒被引入的併發工具類還有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它們都存在於java.util.concurrent包下。CountDownLatch這個類可以使一個線程等待其餘線程完成各自的工做後再執行。例如,應用程序的主線程但願在負責啓動框架服務的線程已經啓動全部的框架服務以後再執行。
CountDownLatch是經過一個計數器來實現的,計數器的初始值爲線程的數量。每當一個線程完成了本身的任務後,計數器的值就會減1。當計數器值到達0時,它表示全部的線程已經完成了任務,而後在閉鎖上等待的線程就能夠恢復執行任務。java
調用CountDownLatch類的await()方法會一直阻塞,直到其餘線程調用CountDown()方法使計數器的值減1,當計數器的值等於0則當因調用await()方法處於阻塞狀態的線程會被喚醒繼續執行。計數器是不能被重置的。這個類使用線程在達到某個條件後繼續執行的狀況。好比並行計算,計算量特別大,我能夠將計算量拆分紅多個線程進行計算,最後將結果彙總。併發
一個CountdownLatch 例子框架
@Slf4j public class CountDownLatchExample1 { private final static int threadCount = 200; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { test(threadNum); } catch (Exception e) { log.error("exception", e); } finally { countDownLatch.countDown(); } }); } countDownLatch.await(); log.info("finish"); exec.shutdown(); } private static void test(int threadNum) throws Exception { Thread.sleep(100); log.info("{}", threadNum); Thread.sleep(100); } }
咱們在線程以後都調用了countDown方法,在執行log以前調用了await方法,從而來保證打印日誌時必定是在全部線程執行完。假設咱們不使用CountDownLatch時結果會怎麼樣?工具
@Slf4j public class CountDownLatchExample1 { private final static int threadCount = 200; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final CountDownLatch countDownLatch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { test(threadNum); } catch (Exception e) { log.error("exception", e); } // finally { //// countDownLatch.countDown(); // } }); } // countDownLatch.await(); log.info("finish"); // exec.shutdown(); } private static void test(int threadNum) throws Exception { Thread.sleep(100); log.info("{}", threadNum); Thread.sleep(100); } }
這段代碼打印結果就是,一開始就打印出了finish,由於這個打印是在主線程中執行。spa