https://blog.csdn.net/qq_34997906/article/details/93459237
1. 使用join()方法,讓主線程等待
join的意思是使得放棄當前線程的執行,等待引用線程執行完畢。
public class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": 開始執行。。。");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 執行結束。。。");
}
}
public class JoinTest {
public static void main(String[] args) {
List<Thread> list = new ArrayList<>();
for(int i = 0; i < 4; i++) {
Thread thread = new Thread(new MyThread());
thread.start();
list.add(thread);
}
try {
// 讓每一個子線程都阻塞,等到
for(Thread thread : list) {
// 每循環一次都將阻塞一次,直到該子線程執行完畢後,再繼續循環執行下一個子線程的join
thread.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有子線程執行完畢了。。。");
}
}
輸出:
Thread-0: 開始執行。。。
Thread-1: 開始執行。。。
Thread-2: 開始執行。。。
Thread-3: 開始執行。。。
Thread-0: 執行結束。。。
Thread-3: 執行結束。。。
Thread-2: 執行結束。。。
Thread-1: 執行結束。。。
所有子線程執行完畢了。。。
2. 使用CountDownLatch
CountDownLatch是一個異步輔助類,它能讓一個和多個線程處於等待狀態,直到其他線程完成了一些列操作。
class Work implements Runnable {
private CountDownLatch latch;
public Work(CountDownLatch latch){
this.latch = latch;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": 開始執行。。。");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
System.out.println(Thread.currentThread().getName() + ": 執行結束。。。");
latch.countDown();
}
}
}
public class CountDownLautchTest {
public static void main(String[] args) {
// 此處的數字應定義爲創建的任務數,而不是線程池的大小
final CountDownLatch latch = new CountDownLatch(4);
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 4; i++) {
executorService.execute(new Work(latch));
}
try {
latch.await();
System.out.println("所有子線程執行完畢了。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
輸出:
pool-1-thread-1: 開始執行。。。
pool-1-thread-2: 開始執行。。。
pool-1-thread-3: 開始執行。。。
pool-1-thread-2: 執行結束。。。
pool-1-thread-3: 執行結束。。。
pool-1-thread-1: 執行結束。。。
pool-1-thread-2: 開始執行。。。
pool-1-thread-2: 執行結束。。。
所有子線程執行完畢了。。。
小結:顯然在等待多個線程的時候,CountDownLatch比join的方式更方便也更直觀,join的方式需要在主線程中爲每一個子線程調用一次,否則會漏掉,每調用一次,主線程就會被阻塞一次,然後在執行下一次的join3. 使用線程池的awaitTermination()方法
public class ExecutorAwait {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 4; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": 開始執行。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 執行結束。。。");
}
};
executorService.execute(runnable);
}
try {
executorService.shutdown();
// awaitTermination返回false即超時會繼續循環,返回true即線程池中的線程執行完成主線程跳出循環往下執行,每隔5秒循環一次
while (!executorService.awaitTermination(5, TimeUnit.SECONDS)){
// 超時等待後,可以手動結束所有正常執行的線程。不執行下面的語句將循環等待,直到所有子線程結束。
// executorService.shutdownNow();
}
System.out.println("所有子線程執行完畢了。。。");
} catch (Exception e) {
e.printStackTrace();
}
}
}