主執行緒等待所有其他執行緒執行完畢,然後再繼續執行主執行緒的邏輯,有以下幾種方法可以實現:

溪因發表於2024-08-13
## 1. 使用 `Thread.join()`
`Thread.join()` 方法會讓主執行緒等待被呼叫執行緒執行完畢之後再繼續執行。

#### 示例程式碼:

```java
public class Main {
public static void main(String[] args) {
// 建立3個執行緒
Thread thread1 = new Thread(() -> {
System.out.println("Thread 1 is running");
// 模擬任務耗時
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 1 is done");
});

Thread thread2 = new Thread(() -> {
System.out.println("Thread 2 is running");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 2 is done");
});

Thread thread3 = new Thread(() -> {
System.out.println("Thread 3 is running");
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 3 is done");
});

// 啟動執行緒
thread1.start();
thread2.start();
thread3.start();

try {
// 主執行緒等待子執行緒執行完畢
thread1.join();
thread2.join();
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

// 主執行緒繼續執行
System.out.println("All threads have finished. Main thread continues.");
}
}
```

#### 解釋:
- `thread1.join()` 會讓主執行緒等待 `thread1` 執行完畢後再繼續往下執行。
- `thread2.join()` 和 `thread3.join()` 也類似。
- 當所有執行緒都執行完畢後,主執行緒會繼續執行接下來的邏輯。

### 2. 使用 `ExecutorService` 和 `awaitTermination()`
`ExecutorService` 提供了管理執行緒池的能力,使用它可以方便地等待所有任務執行完畢。

#### 示例程式碼:

```java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);

// 提交3個任務
executor.submit(() -> {
System.out.println("Task 1 is running");
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Task 1 is done");
});

executor.submit(() -> {
System.out.println("Task 2 is running");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Task 2 is done");
});

executor.submit(() -> {
System.out.println("Task 3 is running");
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Task 3 is done");
});

// 停止接收新的任務,並等待已提交任務執行完畢
executor.shutdown();

try {
// 等待所有任務完成,最多等待10分鐘
if (!executor.awaitTermination(10, TimeUnit.MINUTES)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}

// 主執行緒繼續執行
System.out.println("All tasks have finished. Main thread continues.");
}
}
```

#### 解釋:
- `executor.shutdown()` 會停止接收新的任務,但會讓已經提交的任務繼續執行。
- `executor.awaitTermination()` 會等待所有任務完成,等待的時間可以設定。如果超時或者被中斷,可以呼叫 `shutdownNow()` 來強制終止所有執行緒。

### 3. 使用 `CountDownLatch`
`CountDownLatch` 是一個同步輔助類,用於在一個或多個執行緒完成一組操作之前,使一個或多個執行緒等待。

#### 示例程式碼:

```java
import java.util.concurrent.CountDownLatch;

public class Main {
public static void main(String[] args) {
int numberOfThreads = 3;
CountDownLatch latch = new CountDownLatch(numberOfThreads);

// 建立並啟動3個執行緒
new Thread(() -> {
System.out.println("Thread 1 is running");
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 1 is done");
latch.countDown(); // 執行緒結束時,計數器減1
}).start();

new Thread(() -> {
System.out.println("Thread 2 is running");
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 2 is done");
latch.countDown(); // 執行緒結束時,計數器減1
}).start();

new Thread(() -> {
System.out.println("Thread 3 is running");
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("Thread 3 is done");
latch.countDown(); // 執行緒結束時,計數器減1
}).start();

try {
// 主執行緒等待,直到計數器變為0
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

// 主執行緒繼續執行
System.out.println("All threads have finished. Main thread continues.");
}
}
```

#### 解釋:
- 每個執行緒在執行完任務後呼叫 `latch.countDown()`,減少計數。
- 主執行緒呼叫 `latch.await()` 等待,直到計數器變為0,即所有執行緒都完成了任務。

### 總結
- **`Thread.join()`** 是最簡單直接的方式,但需要手動管理每個執行緒。
- **`ExecutorService`** 提供了更強大的執行緒池管理和任務控制功能。
- **`CountDownLatch`** 非常適合需要在多個執行緒完成各自任務後,再讓主執行緒繼續的場景。

根據具體的應用場景和需求,選擇最合適的方法來實現。

相關文章