有两种方式可以实现,使用CountDownLatch计数或者使用Future模式阻塞获取所有线程的返回结果,待所有线程都执行完毕,主线程再继续执行。
1:使用CountDownLatch计数的方式
package cn.arbexpress.clientmanager.xiangxue;
import java.util.concurrent.CountDownLatch;
/**
* DESCRIPTION:使用CountDownLatch
*
* @author liu.qq
* @create 2019-09-17 15:08
**/
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDown = new CountDownLatch(1);
CountDownLatch await = new CountDownLatch(5);
// 依次创建并启动处于等待状态的5个MyRunnable线程
for (int i = 0; i < 5; ++i) {
new Thread(new MyRunnable(countDown, await)).start();
}
System.out.println("用于触发处于等待状态的线程开始工作......");
System.out.println("用于触发处于等待状态的线程工作完成,等待状态线程开始工作......");
countDown.countDown();
await.await();
System.out.println("Bingo!");
}
public static class MyRunnable implements Runnable {
private final CountDownLatch countDown;
private final CountDownLatch await;
public MyRunnable(CountDownLatch countDown, CountDownLatch await) {
this.countDown = countDown;
this.await = await;
}
public void run() {
try {
countDown.await();//等待主线程执行完毕,获得开始执行信号...
System.out.println("处于等待的线程开始自己预期工作......");
await.countDown();//完成预期工作,发出完成信号...
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2:使用Future模式来阻塞有返回值的子线程执行完毕,再去执行主线程
package cn.arbexpress.clientmanager.xiangxue;
import java.util.Random;
import java.util.concurrent.*;
/**
* DESCRIPTION:
*
* @author liu.qq
* @create 2019-09-17 15:19
**/
public class FutureTaskTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
//使用CompletionService可以按照任务的完成顺序依次获取返回结果,而不是任务的提交顺序
CompletionService<Integer> completionService = new ExecutorCompletionService(executor);
int taskSize = 10;
//提交10个任务到线程池执行
for(int i=0;i<taskSize;i++){
try {
TimeUnit.SECONDS.sleep(1);
completionService.submit(new Task(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//上述任务执行的过程中同步获取任务的执行结果
for(int i=0;i<taskSize;i++){
try {
//注意是take方法
Future<Integer> takeResult = completionService.take();
//阻塞直到获取到执行结果
Integer result = takeResult.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//关闭线程池
executor.shutdown();
System.out.println("主线程在执行任务");
System.out.println("所有任务执行完毕");
}
}
class Task implements Callable<Integer> {
private int i;
public Task(int i) {
this.i = i;
}
@Override
public Integer call() throws Exception {
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
return i;
}
}
总结:这两种方式都可以阻塞主线程,待子线程执行完毕再执行主线程,一般使用CountDownLatch处理没有返回值的任务,使用Future模式来处理有返回值的情况。欢迎大家批评指正。