# 面试官:多个线程执行完毕后,才执行另一个线程,该怎么做?

在这里插入图片描述

# CountDownLatch

去掉try catch版本

public static void main(String[] args) throws InterruptedException {

	/**
	 * Thread-1 在路上耗时4秒
	 * Thread-2 在路上耗时0秒
	 * Thread-0 在路上耗时4秒
	 * Thread-2 到达车站了
	 * Thread-1 到达车站了
	 * Thread-0 到达车站了
	 * 老司机,发车
	 */
	CountDownLatch countDownLatch = new CountDownLatch(3);
	Random random = new Random();
	for (int i = 0; i < 3; i++) {
		new Thread(() -> {
			//返回[0,5)的值
			int time = random.nextInt(5);
			System.out.println(Thread.currentThread().getName() + " 在路上耗时" + time + "秒");
			TimeUnit.SECONDS.sleep(time);
			System.out.println(Thread.currentThread().getName() + " 到达车站了");
			countDownLatch.countDown();
		}).start();
	}
	countDownLatch.await();
	System.out.println("老司机,发车");
}

先来演示一下用法,可以看到所有子线程都执行完毕才会执行主线程。实现这个功能主要靠的是CountDownLatch的2个方法await()和countDown()。

new一个CountDownLatch时会传一个计数器的值,上面的例子为3。调用await()方法时判断计数是否为0,如果不为0则呈等待状态。其他线程可以调用countDown()方法将计数减1,当计数减到位0时,则呈等待的线程继续执行。

# CyclicBarrier

去掉try catch版本

public static void main(String[] args) {

	/**
	 * Thread-1 在路上耗时0秒
	 * Thread-2 在路上耗时2秒
	 * Thread-1 到达车站了
	 * Thread-0 在路上耗时3秒
	 * Thread-2 到达车站了
	 * Thread-0 到达车站了
	 * 老司机,发车
	 */
	CyclicBarrier cyclicBarrier = new CyclicBarrier(3, ()->{
		System.out.println("老司机,发车");
	});
	Random random = new Random();
	for (int i = 0; i < 3; i++) {
		new Thread(() -> {
			//返回[0,5)的值
			int time = random.nextInt(5);
			System.out.println(Thread.currentThread().getName() + " 在路上耗时" + time + "秒");
			TimeUnit.SECONDS.sleep(time);
			System.out.println(Thread.currentThread().getName() + " 到达车站了");
			cyclicBarrier.await();
		}).start();
	}
}

CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置。挺简单的就不再演示。因为这2个工具类都用到了AQS,而AQS的原理很长,因此在本文就不介绍AQS的实现了

# CompletableFuture

去掉try catch版本

public static void main(String[] args) {
    /**
     * ForkJoinPool.commonPool-worker-1 在路上耗时4秒
     * ForkJoinPool.commonPool-worker-2 在路上耗时3秒
     * ForkJoinPool.commonPool-worker-1 到达车站了
     * ForkJoinPool.commonPool-worker-2 到达车站了
     * 老司机,发车
     */
    Random random = new Random();
    CompletableFuture future1 = CompletableFuture.runAsync(() -> {
        int time = random.nextInt(5);
        System.out.println(Thread.currentThread().getName() + " 在路上耗时" + time + "秒");
        TimeUnit.SECONDS.sleep(random.nextInt());
        System.out.println(Thread.currentThread().getName() + " 到达车站了");
    });
    CompletableFuture future2 = CompletableFuture.runAsync(() -> {
        int time = random.nextInt(5);
        System.out.println(Thread.currentThread().getName() + " 在路上耗时" + time + "秒");
        TimeUnit.SECONDS.sleep(random.nextInt());
        System.out.println(Thread.currentThread().getName() + " 到达车站了");
    });
    CompletableFuture.allOf(future1, future2).thenRun(() -> {
        System.out.println("老司机,发车");
    });
}