面试官:如何让主线程等待所有的子线程结束之后再执行?我懵了
当面试官问你,如何让主线程等待所有的子线程结束之后再执行?你知道吗?本篇就带给大家这个问题的答案。
- 作者:java小当家来源:今日头条|2021-04-08 10:51
使用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("主线程结束");
- }
- }
join()方法使得主线程等待子线程执行结束,阻塞的是主线程。其底层原理,可以参考我的这篇文章你真得懂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();
- }
- });
- //不再接受新的任务
- pool.shutdown();
- while (true) {
- //手动循环确实效率很低,不推荐
- if (pool.isTerminated()) {
- System.out.println("线程池中的任务执行结束");
- break;
- }
- }
- System.out.println("主线程结束");
- }
- }
isTerminated,当调用shutdown()方法后,并且所有提交的任务完成后才会返回为true
这里直接使用了固定大小的线程池,线程池的参数在面试中也经常被问到,对线程池不熟悉的同学,可以参考我的这篇文章说说线程池
使用Future机制
- 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;
- });
- //不再接受新的任务
- pool.shutdown();
- //get方法为阻塞获取
- System.out.println("task1的运行结果:" + task1.get());
- System.out.println("task2的运行结果:" + task2.get());
- System.out.println("主线程结束");
- }
- }
Future机制,可以参考我的另外一篇博客谈谈Future、Callable、FutureTask关系
使用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("主线程结束");
- }
- }
每调用一次countDown方法,计数器会减1,在计数器减为0之前,await方法将会阻塞主线程。有关CountDownLatch的底层原理,可以参考我的另外一篇博客CountDownLatch实现原理
使用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("计算结果为" + cf.get());
- System.out.println("主线程结束");
- }
- }
等到两个子任务都完成后,输出两数之积,再执行主线程。对CompletableFuture不熟悉的同学,可以参考我的这一篇文章什么,你还不会用CompletableFuture?
【编辑推荐】
【责任编辑:姜华 TEL:(010)68476606】
点赞 0
- 大家都在看
- 猜你喜欢
编辑推荐
- 24H热文
- 一周话题
- 本月获赞
- 太厉害了,终于有人能把TCP/IP协议讲的明明白白了!坐在马桶上看算法:快速排序花了一个星期,我终于把RPC框架整明白了!图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)开发 | 再见了,公司的“烂系统”6种微服务RPC框架,你知道几个?架构师的选择,Pulsar还是Kafka?终于有人把Elasticsearch原理讲透了!
- 太厉害了,终于有人能把TCP/IP协议讲的明明白白了!坐在马桶上看算法:快速排序花了一个星期,我终于把RPC框架整明白了!图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)6种微服务RPC框架,你知道几个?架构师的选择,Pulsar还是Kafka?五大自动化测试的Python框架终于有人把Elasticsearch原理讲透了!
- 太厉害了,终于有人能把TCP/IP协议讲的明明白白了!坐在马桶上看算法:快速排序花了一个星期,我终于把RPC框架整明白了!6种微服务RPC框架,你知道几个?图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)五大自动化测试的Python框架Java对象为啥要实现Serializable接口?Java 16 正式发布,已经是Java 8的两倍了
订阅专栏+更多
-
数据湖与数据仓库的分析实践攻略
助力现代化数据管理:数据湖与数据仓库的分析实践攻略共3章 | 创世达人7人订阅学习
-
云原生架构实践
新技术引领移动互联网进入急速赛道共3章 | KaliArch37人订阅学习
-
数据中心和VPDN网络建设案例
漫画+案例共20章 | 捷哥CCIE230人订阅学习
视频课程+更多
-
标杆徐全新Linux云计算运维系列②: web集群架
讲师:徐亮伟90945人学习过
-
Elasticsearch分布式数据库与ELK大数据平台实
讲师:风哥8630人学习过
-
Linux运维+云计算实战班(Linux云计算、K8S、
讲师:IT学院13926人学习过
专题推荐+更多
-
订阅51CTO邮刊
点击这里查看样刊

51CTO服务号

51CTO官微