先上一個介紹:https://blog.csdn.net/shihuacai/article/details/8856370
用視頻https://www.bilibili.com/video/av81181427 中的一個例子來測試
@Test
public void countdownlatch ()throws InterruptedException {
/*
這個5不能循環,減到0了之后await作用就消失了
*/
CountDownLatch countDownLatch=new CountDownLatch(5);
for(int i=0;i<5;i++){
new Thread(()->{
try{
Thread.sleep(new Double(Math.random()*3000).longValue());
System.out.println(Thread.currentThread().getName()+"玩家准備就緒");
countDownLatch.countDown();//計數點
System.out.println(Thread.currentThread().getName()+"玩家選擇英雄");
}catch (InterruptedException e){
e.printStackTrace();
}
}).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"開始游戲");
//Thread.sleep(3000);
}
輸出為:
Thread-0玩家准備就緒
Thread-0玩家選擇英雄
Thread-2玩家准備就緒
Thread-2玩家選擇英雄
Thread-4玩家准備就緒
Thread-4玩家選擇英雄
Thread-3玩家准備就緒
Thread-3玩家選擇英雄
Thread-1玩家准備就緒
Thread-1玩家選擇英雄
main開始游戲
實際上,CountDownLatch阻塞的是主線程而非子線程,這一點要弄清楚。子線程中countDownLatch.countDown();唯一的作用就是將CountDownLatch對象內部的計數器減一,它不能起到阻塞子線程的作用。唯一受到阻塞的是創建完子線程后執行countDownLatch.await();語句的父線程,只有CountDownLatch對象內的計數器減到0之后主線程才能繼續執行,而這和子線程的執行無關。
說明這一點最直觀的方式是讓CountDownLatch的初始參數比線程數小,我們把參數調成5,用10個線程。看看輸出是什么:
Thread-4玩家准備就緒
Thread-4玩家選擇英雄
Thread-7玩家准備就緒
Thread-7玩家選擇英雄
Thread-6玩家准備就緒
Thread-6玩家選擇英雄
Thread-5玩家准備就緒
Thread-5玩家選擇英雄
Thread-3玩家准備就緒
Thread-3玩家選擇英雄
main開始游戲
為什么只有5個子線程執行的結果,剩下的5個子線程去哪里了?別急,我們在主線程的代碼末尾加一句sleep語句:
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"開始游戲");
Thread.sleep(3000);
再次執行,結果是:
Thread-7玩家准備就緒
Thread-7玩家選擇英雄
Thread-9玩家准備就緒
Thread-9玩家選擇英雄
Thread-2玩家准備就緒
Thread-2玩家選擇英雄
Thread-6玩家准備就緒
Thread-6玩家選擇英雄
Thread-0玩家准備就緒
Thread-0玩家選擇英雄
main開始游戲
Thread-5玩家准備就緒
Thread-5玩家選擇英雄
Thread-4玩家准備就緒
Thread-4玩家選擇英雄
Thread-1玩家准備就緒
Thread-1玩家選擇英雄
Thread-3玩家准備就緒
Thread-3玩家選擇英雄
Thread-8玩家准備就緒
Thread-8玩家選擇英雄
可以看出,之前剩下五個子線程的內容輸出不出來,是因為父線程執行完后函數返回了。但是我們知道,父線程和子線程是獨立執行的。這是為什么?
其實這是因為我使用的是Junit測試方法,而Junit不支持多線程而已,這個帖子就提到了這一點:在junit單元測試中,當創建了新線程后,單元測試並不會等待主線程下啟動的新線程是否執行結束,只要主線程結束完成,單元測試就會關閉,導致主線程中啟動的新線程不能順利執行完.所以剩下的五個線程還沒有執行就被銷毀了。
換成普通的main方法再試試:
Thread-0玩家准備就緒
Thread-0玩家選擇英雄
Thread-5玩家准備就緒
Thread-5玩家選擇英雄
Thread-3玩家准備就緒
Thread-3玩家選擇英雄
Thread-1玩家准備就緒
Thread-1玩家選擇英雄
Thread-9玩家准備就緒
Thread-9玩家選擇英雄
main開始游戲
Thread-7玩家准備就緒
Thread-7玩家選擇英雄
Thread-8玩家准備就緒
Thread-8玩家選擇英雄
Thread-2玩家准備就緒
Thread-2玩家選擇英雄
Thread-6玩家准備就緒
Thread-6玩家選擇英雄
Thread-4玩家准備就緒
Thread-4玩家選擇英雄
Process finished with exit code 0
這回就正常了
那如果CountDownLatch的初始參數比線程數大會發生什么,我們把參數調成10,用5個線程。
Thread-2玩家准備就緒
Thread-2玩家選擇英雄
Thread-1玩家准備就緒
Thread-1玩家選擇英雄
Thread-0玩家准備就緒
Thread-0玩家選擇英雄
Thread-4玩家准備就緒
Thread-4玩家選擇英雄
Thread-3玩家准備就緒
Thread-3玩家選擇英雄
實際上,雖然子線程都執行完了,程序還是不會停止的,因為CountDownLatch內的計數器不會被減到0,main線程一直處於阻塞狀態。