當在執行多執行的程式時,如果有一個執行緒需要等待其它執行緒都執行再繼續使用。則可以考慮使用 java.util.concurrent package 下的 CountDownLatch 類別。在new CountDownLatch 的物件時會在建構子裡會指定需要等待多少數量的執行緒,當在執行一個執行緒時這個 count 值就會被減掉 1,等到減到 0 時就代表所有的執行緒都被執行完成了,等待的執行緒就繼續的往下執行。
以下是撰寫使用 CountDownLatch 類別的 Sample Code:
import java.util.concurrent.CountDownLatch;
public class CountDownThreadExample implements Runnable {
private CountDownLatch countDownLatch;
public CountDownThreadExample(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
String currentThread = Thread.currentThread().getName();
System.out.println("current Thread:" + currentThread);
} catch(Exception e) {
throw new RuntimeException(e);
} finally {
this.countDownLatch.countDown();
}
}
}
以上的執行緒程式主要會接收主程式傳來的 CountDownLatch 物件,然後在 run 的方法裡把目前執行的執行緒名稱印出來,等執行完畢之會會呼叫 countDown 使得 countDown 建構子設定的數值會減掉 1,等減到 0 時就可以執行主程式 await 方法後面的程式, 主程式的寫法如下:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String args[]) {
ExecutorService es = Executors.newFixedThreadPool(5);
try {
CountDownLatch cdt = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
es.execute(new CountDownThreadExample(cdt));
}
cdt.await();
System.out.println("thread running finish");
} catch(Exception e) {
throw new RuntimeException(e);
} finally {
es.shutdown();
}
}
}
在主程式裡會使用 Executors 建立固定的執行緒 pool,之後會建立 CountDownLatch 的 instance,在建構子裡面會傳入 5 就是要等待 5 個執行緒的程式執行完之後才會執行 await 方法後面的程式印出 thread running finish 的字串,執行的結果如下:
current Thread:pool-1-thread-1
current Thread:pool-1-thread-2
current Thread:pool-1-thread-4
current Thread:pool-1-thread-3
current Thread:pool-1-thread-5
thread running finish
從以上的結果可以看出 thread running finish 的字串,一定會等到所有的執行緒執行完之後才會被印出來。
CountDownLatch 常被使用到的情境是當要啟動一個服務 service 時,會先去檢查一些環境的設定例如 DB 是否可以連線、 Storage 是否有系統所需要的資料夾、時間設定是否正確…等等的檢查這時就可以開很多的 thread 去做檢查,並且套用 CountDownLatch 類別,等到所有的檢查都正確時再往下的執行 service 其它的工作。