一.場景引入
教師裏有很多學生,比如說有7個,其中一個是班長,他負責在全員離開後關閉大門,現在要實現一個程序,其中包括main線程在內有七個線程,main是班長。
需求是:班長要在所有人都離開教室之後才關閉大門,也就是說main線程需要在所有線程運行完之後纔打印這條語句
public static void main(String[] args) {
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t離開教室。");
},String.valueOf(i)).start();
}
System.out.println("班長離開,關門。。。");
}
這樣能實現我們的要求嗎?:
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=52240:D:\idea\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\李肇京\IdeaProjects\JUC\out\production\JUC" JUC_01_SellTicket.HelperClasses.CountDownLatchDemo
班長離開,關門。。。
1 離開教室。
4 離開教室。
3 離開教室。
2 離開教室。
5 離開教室。
6 離開教室。
Process finished with exit code 0
你可以多試幾次,可能會出現符合條件的情況,但是這並不是穩定情況,不能滿足我們的需求。
二.CountDownLatch介紹
- countDownLatch存在於java.util.cucurrent包下,是JUC輔助類的一種
- countDownLatch這個類實現的功能是:使一個線程等待其他線程各自執行完畢後再執行
- 是通過一個計數器來實現的,計數器的初始值是線程的數量。每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,表示所有線程都執行完畢,然後在閉鎖上等待的線程就可以恢復工作了
怎麼加在我們的代碼中?:
public static void main(String[] args) throws InterruptedException {
//1.創建對象
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6 ; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t離開教室。");
countDownLatch.countDown();//2.計數
},String.valueOf(i)).start();
}
countDownLatch.await();//main線程等待
System.out.println("班長離開,關門。。。");
}
三.原理
CountDownLatch中有三個關鍵的方法
//調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續執行
public void await() throws InterruptedException { };
//和await()類似,只不過等待一定的時間後count值還沒變爲0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//將count值減1
public void countDown() { };
CountDownLatch只有一個構造器:
//參數count爲計數值
public CountDownLatch(int count) { };
它要求我們提供一個count用來計數,也就是用來規定有幾個線程是要先執行的,這裏我們有6個學生要離開教室,所以傳入6.
由於主線程打印之前有一條語句countDownLatch.await(),所以main線程不會直接打印,而是等待循環內部將計數器逐漸減少,知道其值爲0,此時main繼續執行。這樣就完成了我們的需求。