面試官:如何讓主線程等待所有的子線程結(jié)束之后再執(zhí)行?我懵了
使用Thread的join方法
- package com.qcy.testThreadFinish;
- /**
- * @author qcy
- * @create 2020/09/09 17:05:23
- */
- public class Case1 {
- public static void main(String[] args) throws InterruptedException {
- Thread t1 = new Thread(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- t1.start();
- Thread t2 = new Thread(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- t2.start();
- t1.join();
- t2.join();
- System.out.println("主線程結(jié)束");
- }
- }
join()方法使得主線程等待子線程執(zhí)行結(jié)束,阻塞的是主線程。其底層原理,可以參考我的這篇文章你真得懂Thread.join嗎?
使用線程池的isTerminated方法
- package com.qcy.testThreadFinish;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- /**
- * @author qcy
- * @create 2020/09/09 17:05:23
- */
- public class Case2 {
- public static void main(String[] args) {
- ExecutorService pool = Executors.newFixedThreadPool(3);
- pool.execute(() -> {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- pool.execute(() -> {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- });
- //不再接受新的任務(wù)
- pool.shutdown();
- while (true) {
- //手動(dòng)循環(huán)確實(shí)效率很低,不推薦
- if (pool.isTerminated()) {
- System.out.println("線程池中的任務(wù)執(zhí)行結(jié)束");
- break;
- }
- }
- System.out.println("主線程結(jié)束");
- }
- }
isTerminated,當(dāng)調(diào)用shutdown()方法后,并且所有提交的任務(wù)完成后才會(huì)返回為true
這里直接使用了固定大小的線程池,線程池的參數(shù)在面試中也經(jīng)常被問(wèn)到,對(duì)線程池不熟悉的同學(xué),可以參考我的這篇文章說(shuō)說(shuō)線程池
使用Future機(jī)制
- package com.qcy.testThreadFinish;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
- /**
- * @author qcy
- * @create 2020/09/09 17:05:23
- */
- public class Case4 {
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- ExecutorService pool = Executors.newFixedThreadPool(3);
- Future<Integer> task1 = pool.submit(() -> {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return 2;
- });
- Future<Integer> task2 = pool.submit(() -> {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return 3;
- });
- //不再接受新的任務(wù)
- pool.shutdown();
- //get方法為阻塞獲取
- System.out.println("task1的運(yùn)行結(jié)果:" + task1.get());
- System.out.println("task2的運(yùn)行結(jié)果:" + task2.get());
- System.out.println("主線程結(jié)束");
- }
- }
Future機(jī)制,可以參考我的另外一篇博客談?wù)凢uture、Callable、FutureTask關(guān)系
使用CountDownLatch
- package com.qcy.testThreadFinish;
- import java.util.concurrent.CountDownLatch;
- /**
- * @author qcy
- * @create 2020/09/09 17:05:23
- */
- public class Case5 {
- public static void main(String[] args) throws InterruptedException {
- CountDownLatch latch = new CountDownLatch(2);
- Thread t1 = new Thread(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- latch.countDown();
- }
- });
- t1.start();
- Thread t2 = new Thread(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- latch.countDown();
- }
- });
- t2.start();
- latch.await();
- System.out.println("主線程結(jié)束");
- }
- }
每調(diào)用一次countDown方法,計(jì)數(shù)器會(huì)減1,在計(jì)數(shù)器減為0之前,await方法將會(huì)阻塞主線程。有關(guān)CountDownLatch的底層原理,可以參考我的另外一篇博客CountDownLatch實(shí)現(xiàn)原理
使用CompletableFuture
- package com.qcy.testThreadFinish;
- import java.util.concurrent.CompletableFuture;
- import java.util.concurrent.ExecutionException;
- /**
- * @author qcy
- * @create 2020/09/09 17:05:23
- */
- public class Case6 {
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return 2;
- });
- CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(() -> {
- try {
- Thread.sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- return 3;
- }).thenCombine(cf1, (result1, result2) -> result1 * result2);
- //get方法為阻塞獲取
- System.out.println("計(jì)算結(jié)果為" + cf.get());
- System.out.println("主線程結(jié)束");
- }
- }
等到兩個(gè)子任務(wù)都完成后,輸出兩數(shù)之積,再執(zhí)行主線程。對(duì)CompletableFuture不熟悉的同學(xué),可以參考我的這一篇文章什么,你還不會(huì)用CompletableFuture?