【Java并发编程】主线程等待子线程的多种方法
文章目录
- 1.Thread sleep()
- 2.Thread join()
- 3.synchronized 等待唤醒机制
- 4.ExecutorService isTerminated() + while 轮询判断
- 5.ExecutorService awaitTermination()
- 6.Future
- 7.CountDownLatch
- 8.CyclicBarrier
- 9.BlockingQueue
- 10.CompletableFuture(本质还是Future的get方法)
- 11.LockSupport(23.03.17更新)
提醒:
1 部分案例使用线程池创建线程。方便起见使用Executors.newFixedThreadPool()方法创建一个固定大小的线程池。
2 Runnable使用Lambda表达式创建
3 代码在main()方法中执行,出于方便演示,代码中有几处不规范的地方
4 JDK使用17版本
1.Thread sleep()
public static void main(String[] args) throws Exception {long timeout1 = 1000;long timeout2 = timeout1 + 500;new Thread(() -> {try {Thread.sleep(timeout1);} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();// 满足 timeout2 > timeout1 即可Thread.sleep(timeout2);System.out.println("主线程执行!\ndo something...");
}
方法问题太多,不可取,仅作为参考
2.Thread join()
private static void test06() throws Exception {CopyOnWriteArrayList<Thread> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 3; i++) {Thread thread = new Thread(() -> {try {// 随机生成睡眠时间long timeout = new Random().nextLong(1000, 3000);TimeUnit.MILLISECONDS.sleep(timeout);System.out.printf("%s 子线程执行完毕!耗时:%sms\n", Thread.currentThread().getName(), timeout);} catch (InterruptedException e) {throw new RuntimeException(e);}});list.add(thread);thread.start();}for (Thread thread : list) {thread.join();}System.out.println("主线程执行!\ndo something...");
}
3.synchronized 等待唤醒机制
public static void main(String[] args) throws Exception {Object lock = new Object();// 启动子线程new Thread(() -> {try {TimeUnit.SECONDS.sleep(1);System.out.println("子线程执行完毕");// 获取对象锁synchronized (lock) {// 子线程唤醒lock.notify();}} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();synchronized (lock) {// 主线程等待lock.wait();}System.out.println("主线程执行!\ndo something...");
}
4.ExecutorService isTerminated() + while 轮询判断
思路:所有任务提交后,调用线程池的shutdown()方法,然后在死循环里每隔几秒调用一次线程池的isTerminated()方法,判断所有线程在线程池关闭后是否都已完成。需要注意的是调用isTerminated()前一定要先调用shutdown()或shutdownNow()方法,原因可以在isTerminated()的源码中找到,位于java.util.concurrent.ExecutorService 198行左右,内容如下:
翻译为中文:如果所有任务在关闭后都已完成,则返回 true。请注意,除非首先调用了 shutdown 或 shutdownNow,否则 isTerminated 永远不会为真。
实现代码:
public static void main(String[] args) throws Exception {int n = 3;String[] tasks = {"发送短信消息完毕", "发送微信消息完毕", "发送邮箱消息完毕"};int[] executeTimes = new int[]{2, 5, 1};ExecutorService threadPool = Executors.newFixedThreadPool(n);long start = System.currentTimeMillis();for (int i = 0; i < n; i++) {int finalI = i;threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(executeTimes[finalI]);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(tasks[finalI]);});}threadPool.shutdown();// 关键代码while (true) {if (threadPool.isTerminated()) {break;} else {// 每隔1s判断一次TimeUnit.SECONDS.sleep(1);}}System.out.println("所有消息都发送完毕了,执行主线程任务。\n耗时ms:" + (System.currentTimeMillis() - start));
}
缺点:若线程池中的任务完成耗时不确定,则不能及时执行主线程的任务
5.ExecutorService awaitTermination()
public static void main(String[] args) throws Exception {ExecutorService executorService = Executors.newFixedThreadPool(3);for (int i = 0; i < 3; i++) {executorService.execute(() -> {long timeout = new Random().nextLong(1000, 3000);try {TimeUnit.MILLISECONDS.sleep(timeout);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.printf("%s 子线程执行完毕!耗时:%sms\n", Thread.currentThread().getName(), timeout);});}executorService.shutdown();// 阻塞当前线程,直到所有已提交的任务完成执行,或者发生超时,或者当前线程中断,以先发生者为准。executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);System.out.println("主线程执行!\ndo something...");
}
6.Future
private static void test03() throws Exception{ExecutorService executorService = Executors.newFixedThreadPool(1);Future<String> future = executorService.submit(() -> {try {System.out.println("do something...");TimeUnit.SECONDS.sleep(1);System.out.println("子线程任务完成");} catch (InterruptedException e) {throw new RuntimeException(e);}return "子线程返回的结果";});System.out.println(future.get());executorService.shutdown();System.out.println("主线程执行!");
}
7.CountDownLatch
public static void main(String[] args) throws Exception {int n = 3;String[] tasks = {"发短信完毕", "发微信完毕", "发QQ完毕"};int[] executeTimes = new int[]{2, 5, 1};CountDownLatch countDownLatch = new CountDownLatch(n);ExecutorService executorService = Executors.newFixedThreadPool(n);long start = System.currentTimeMillis();for (int i = 0; i < n; i++) {int finalI = i;executorService.submit(() -> {try {TimeUnit.SECONDS.sleep(executeTimes[finalI]);System.out.println(tasks[finalI]);} catch (InterruptedException e) {e.printStackTrace();} finally {countDownLatch.countDown();}});}countDownLatch.await();System.out.println("所有消息都发送完毕了,执行主线程任务。\n耗时ms:" + (System.currentTimeMillis() - start));// 不要忘记关闭线程池,不然会导致主线程阻塞无法退出executorService.shutdown();
}
8.CyclicBarrier
private static void test07() throws Exception{CyclicBarrier cyclicBarrier = new CyclicBarrier(6);// 最后一个达到屏障的线程留给主线程,因此循环5次for (int i = 0; i < 5; i++) {new Thread(() -> {long timeout = new Random().nextLong(1000, 3000);try {TimeUnit.MILLISECONDS.sleep(timeout);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.printf("%s 子线程执行完毕!耗时:%sms\n", Thread.currentThread().getName(), timeout);// 到达屏障try {cyclicBarrier.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}}).start();}cyclicBarrier.await();System.out.println("主线程执行!\ndo something...");
}
9.BlockingQueue
public static void main(String[] args) throws Exception {BlockingQueue<String> queue = new ArrayBlockingQueue<>(1);new Thread(() -> {try {TimeUnit.SECONDS.sleep(1);queue.put("OK");} catch (InterruptedException e) {e.printStackTrace();}}).start();System.out.println(queue.take());System.out.println("主线程执行!\ndo something...");
}
10.CompletableFuture(本质还是Future的get方法)
public static void main(String[] args) throws Exception {CompletableFuture<Void> cf1 = CompletableFuture.runAsync(() -> {try {TimeUnit.SECONDS.sleep(1);System.out.println("cf1 任务完成");} catch (InterruptedException e) {throw new RuntimeException(e);}});CompletableFuture<Void> cf2 = CompletableFuture.runAsync(() -> {try {TimeUnit.SECONDS.sleep(2);System.out.println("cf2 任务完成");} catch (InterruptedException e) {throw new RuntimeException(e);}});CompletableFuture<Void> cf3 = CompletableFuture.runAsync(() -> {try {TimeUnit.SECONDS.sleep(0);System.out.println("cf3 任务完成");// int n = 1 / 0;} catch (InterruptedException e) {throw new RuntimeException(e);}});CompletableFuture<Void> allOf = CompletableFuture.allOf(cf1, cf2, cf3);// 若子任务都未发生异常则返回null,否则返回异常。此步会阻塞主线程System.out.println(allOf.get());System.out.println("主线程执行!");
}
11.LockSupport(23.03.17更新)
public static void main(String[] args) {Thread mainThread = Thread.currentThread();new Thread(() -> {try {System.out.println("子线程开始执行");// 模拟子线程执行任务TimeUnit.SECONDS.sleep(2);System.out.println("子线程执行完毕!");} catch (InterruptedException e) {throw new RuntimeException(e);}// 如果线程在 park 上被阻塞,那么它将解除阻塞LockSupport.unpark(mainThread);}).start();// 禁用当前线程(主线程)LockSupport.park();System.out.println("主线程执行!\ndo something...");
}
【Java并发编程】主线程等待子线程的多种方法相关推荐
- java等待5秒_Java并发编程-主线程等待子线程解决方案
主线程等待所有子线程执行完成之后,再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { System.ou ...
- VC++ 中主线程等待子线程结束的方法
void WaitForThreadExit(void) {DWORD dwRet; //返回值MSG msg; int wait_count=4; //线程句柄有4个int nExitThreadC ...
- Java并发编程原理与实战六:主线程等待子线程解决方案
Java并发编程原理与实战六:主线程等待子线程解决方案 参考文章: (1)Java并发编程原理与实战六:主线程等待子线程解决方案 (2)https://www.cnblogs.com/pony1223 ...
- java 主线程等待_Java实现主线程等待子线程
本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...
- Java多线程之----主线程会等待子线程结束再结束么,怎么让主线程等待子线程结束呐?
首先给出结论: 主线程和子线程之间没有谁先谁后结束这种关联,它们只是各自负责自己的线程任务,如果该线程的任务结束了,该线程自然会结束运行. talk is cheap,show me the code ...
- 如何实现java主线程等待子线程执行完毕之后再执行?
本文转自:问题:如何实现java主线程等待子线程执行完毕之后再执行? - jseven - 博客园 点击关注强哥,查看更多精彩文章呀 工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完 ...
- 【多线程】学习记录七种主线程等待子线程结束之后在执行的方法
最近遇到一个问题需要主线程等待所有的子线程结束,才能开始执行,统计所有的子线程执行结果,返回,网上翻阅各种资料,最后记录一下,找到七种方案 第一种:while循环 对于"等待所有的子线程结束 ...
- c++主线程等待子线程结束_简单明了的 Python 多线程来了 | 原力计划
作者 | 万里羊责编 | 王晓曼出品 | CSDN博客线程和进程计算机的核心是CPU,它承担了所有的计算任务,就像是一座工厂在时刻运行.如果工厂的资源有限,一次只能供一个车间来使用,也就是说当一个车间 ...
- Java主线程等待子线程、线程池
public class TestThread extends Thread { public void run() { System.out.println(this.getName() + &qu ...
最新文章
- 蓝桥杯【介绍】和【如何准备才可以拿奖】
- .NET语言的编译过程:中间语言(IL)和即时编译器(JIT)
- how drop down list description is displayed by UI framework
- 剑指offer之求两个链表的第一个公共节点
- 快手上的cosplay大师有多野?
- 1. JanusGraph的优势
- 1052. 卖个萌 (20)-PAT乙级真题
- pip可识别的requirements.txt的写法
- Android MD5加密
- 微信卡券开发错误自排查参考文档
- 上座部佛教的佛陀略传
- [USACO题库]1.2.3 Name That Number命名那个数字
- 【UE4】给制作的小地图加上方向指针
- au能否打开m4a文件_什么是M4V文件(以及如何打开一个文件)?
- ncm 网络_HS-NCM超高速网卡
- Kooboo CMS - 之后台注册用户流程方法。
- Windows 程式设计书籍
- 2022 腾讯社招Golang后端面试经验分享
- RK3399学习笔记 1.0.3---python环境 Firefly Core-3399pro-jd4 Win10上RKNN工具安装
- python中找最小值,使用循环python查找最小值
热门文章
- 【引语练习题】直接引语为疑问句转为间接引语时注意
- Nexus 6 编译并刷机 Android 7.1.1 AOSP以及常用的修改源码快速验证方法
- android6.0升级名单,一加公布Android 6.0升级名单 一加X还要再等等
- linux 内核 strftime,linux 下时间函数strftime()的用法
- 大学数学小屋闲题002-洛必达法则证明
- nginx proxy_redirect 作用
- Texmaker、texstudio 中无法输入中文
- canvas实现图片压缩
- 为什么python注释不能中文_python注释中文
- 不知道怎么向女神表白?Python三大神技分分钟带你成功逆袭!