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();
}
}
}