(面試題)模擬 主程序需要等待多個子程序結束之後再執行後續的程式碼的實現
解法1. Thread.join方法
import java.util.Vector; public class Test { public static void main(String[] args) throws InterruptedException { /* Vector集合: JDK1.0 底層也是陣列 是最早期的同步集合 也就意味著是單執行緒 效率低 實現了list介面所以可以使用list的所有方法 特有方法: void addElement(E obj) 將指定的元件新增到此向量的末尾,將其大小增加 1 Enumeration<E> elements() 返回此向量的元件的列舉(早期的迭代器)。 */ Vector<Thread> vector = new Vector<>(); for (int i = 0; i < 5; i++) { Thread childThread = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("子執行緒被執行"); } }); vector.add(childThread); childThread.start(); } for (Thread thread : vector) { // void join() 等待該執行緒終止 thread.join(); } System.out.println("主執行緒被執行"); } }
解法2.等待多執行緒完成的CountDownLatch
-
1.CountDownLatch的概念: extends Object CountDownLatch是一個同步工具類,用來協調多個執行緒之間的同步 或者說起到執行緒之間的通訊(而不是互斥的作用) CountDownLatch能夠使一個執行緒在等待另一些執行緒完成自己任務後, 再繼續執行.使用一個計數器進行實現,計數器初始值為執行緒的總數量(包括主執行緒). 當每一個執行緒完成自己任務後,計數器的值減一.當計數器的值為0時,表示所有執行緒執行完成, 然後在CountDownLatch上等待的執行緒可以恢復執行任務.
-
2.CountDownLatch的典型用法: 典型用法1: 某一個執行緒開始執行前等待n個執行緒執行完畢.將CountDownLatch的計數器初始化 new CountDownLatch(n),每當一個執行緒完成任務後,計數器的值就會減一 CountDownLatch.countDown(),當計數器的值為0時,在CountDownLatch上await()的執行緒就會被喚醒. 應用場景:啟動一個服務時,主執行緒需要等待多個元件載入完畢之後再繼續執行.
典型用法2:實現多個執行緒開始執行任務的最大並行性.這裡時並行,不是併發, 強調的是多個執行緒在某一時刻同時開始執行.類似於賽跑,將多個執行緒放到七點,等待發令槍,然後同時執行. 做法是初始化一個共享的CountDownLatch(1),將其計數器初始化為1.多個執行緒開始執行任務前首先CountDownLatch.await().當主執行緒呼叫countDown()時,計數器變為0,多個執行緒同時被喚醒.
-
3.CountDownLatch的不足: CountDownLatch是一次性的,計數器的值只能在構造方法中初始化一次,之後沒有任何機制能夠再次對其設定值, 當CountDownLatch使用完畢後,不能再次被呼叫.
public static void main(String[] args) throws InterruptedException {
//建立CountDownLatch並初始化為5
CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
Thread childthread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子執行緒開始執行");
//計數器遞減,為0時釋放所有執行緒
latch.countDown();
}
});
childthread.start();
}
//設定主執行緒等待
latch.await();
System.out.println("主執行緒開始執行");
}