CountDownLatch是經過一個計數器來實現的,當咱們在new 一個CountDownLatch對象的時候須要帶入該計數器值,該值就表示了線程的數量。每當一個線程完成本身的任務後,計數器的值就會減1。當計數器的值變爲0時,就表示全部的線程均已經完成了任務,而後就能夠恢復等待的線程繼續執行了。java
CountDownLatch所描述的是」在完成一組正在其餘線程中執行的操做以前,它容許一個或多個線程一直等待「。在API中是這樣描述的:ide
用給定的計數 初始化 CountDownLatch。因爲調用了 countDown() 方法,因此在當前計數到達零以前,await 方法會一直受阻塞。以後,會釋放全部等待的線程,await 的全部後續調用都將當即返回。這種現象只出現一次——計數沒法被重置。若是須要重置計數,請考慮使用 CyclicBarrier。spa
示例使用開會案例。老闆進入會議室等待5我的所有到達會議室纔會開會。因此這裏有兩個線程老闆等待開會線程、員工到達會議室,下面這段程序有驚天陷阱,請勿copy!:線程
package com.chenjun.testxxx; import java.util.concurrent.CountDownLatch; public class CountDownLatchTest { private static CountDownLatch countDownLatch = new CountDownLatch(5); static class BossThread extends Thread { @Override public void run() { System.out.println("Boss在會議室等待,總共有" + countDownLatch.getCount() + "我的開會..."); try { // Boss等待 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("全部人都已經到齊了,開會吧..."); } // 員工到達會議室 static class EmpleoyeeThread extends Thread { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ",到達會議室...."); }finally { // 員工到達會議室 count - 1 countDownLatch.countDown(); } } } public static void main(String[] args) { // Boss線程啓動 new BossThread().start(); for (long i = 0; i < countDownLatch.getCount(); i++) { new EmpleoyeeThread().start(); } } } }
運行這段程序發現常常程序沒法結束,死等在原地, 緣由就出如今main裏面的for循環那一行,countDownLatch.getCount()是個會變的東西, 用來放在for循環裏面,會影響循環計數,這是個很隱祕的陷阱!code
package com.chenjun.testxxx; import java.util.concurrent.CountDownLatch; public class CountDownLatchTest { private static CountDownLatch countDownLatch = new CountDownLatch(5); static class BossThread extends Thread { @Override public void run() { System.out.println("Boss在會議室等待,總共有" + countDownLatch.getCount() + "我的開會..."); try { // Boss等待 countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("全部人都已經到齊了,開會吧..."); } // 員工到達會議室 static class EmpleoyeeThread extends Thread { @Override public void run() { try { System.out.println(Thread.currentThread().getName() + ",到達會議室...."); }finally { // 員工到達會議室 count - 1 countDownLatch.countDown(); } } } public static void main(String[] args) { // Boss線程啓動 new BossThread().start(); long cnt = countDownLatch.getCount(); for (long i = 0; i < cnt; i++) { new EmpleoyeeThread().start(); } } } }