Java多种方法实现等待所有子线程完成再继续执行

news2025/7/10 22:26:55

简介

在现实世界中,我们常常需要等待其它任务完成,才能继续执行下一步。Java实现等待子线程完成再继续执行的方式很多。我们来一一查看一下。

Thread的join方法

该方法是Thread提供的方法,调用join()时,会阻塞主线程,等该Thread完成才会继续执行,代码如下:

private static void threadJoin() {
  List<Thread> threads = new ArrayList<>();

  for (int i = 0; i < NUM; i++) {
    Thread t = new Thread(new PkslowTask("Task " + i));
    t.start();
    threads.add(t);
  }
  threads.forEach(t -> {
    try {
      t.join();
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  });

  System.out.println("threadJoin Finished All Tasks...");

}

结果:

Task 6 is running
Task 9 is running
Task 3 is running
Task 4 is running
Task 7 is running
Task 0 is running
Task 2 is running
Task 1 is running
Task 5 is running
Task 8 is running
Task 1 is completed
Task 8 is completed
Task 6 is completed
Task 4 is completed
Task 3 is completed
Task 0 is completed
Task 7 is completed
Task 9 is completed
Task 2 is completed
Task 5 is completed
threadJoin Finished All Tasks...

CountDownLatch

CountDownLatch是一个很好用的并发工具,初始化时要指定线程数,如10。在子线程调用countDown()时计数减1。直到为0时,await()方法才不会阻塞。代码如下:

private static void countDownLatch() {
  CountDownLatch latch = new CountDownLatch(NUM);
  for (int i = 0; i < NUM; i++) {
    Thread t = new Thread(() -> {
      System.out.println("countDownLatch running...");
      try {
        Thread.sleep(1000);
        System.out.println("countDownLatch Finished...");
        latch.countDown();
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
    });
    t.start();
  }

  try {
    latch.await();
  } catch (InterruptedException e) {
    throw new RuntimeException(e);
  }
  System.out.println("countDownLatch Finished All Tasks...");
}

结果:

countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch running...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished...
countDownLatch Finished All Tasks...

CyclicBarrier

CyclicBarrier与CountDownLatch类似,但CyclicBarrier可重置,可重用。代码如下:

private static void cyclicBarrier() {
  CyclicBarrier barrier = new CyclicBarrier(NUM + 1);

  for (int i = 0; i < NUM; i++) {
    Thread t = new Thread(() -> {
      System.out.println("cyclicBarrier running...");
      try {
        Thread.sleep(1000);
        System.out.println("cyclicBarrier Finished...");
        barrier.await();
      } catch (InterruptedException | BrokenBarrierException e) {
        throw new RuntimeException(e);
      }
    });
    t.start();
  }

  try {
    barrier.await();
  } catch (InterruptedException | BrokenBarrierException e) {
    throw new RuntimeException(e);
  }
  System.out.println("cyclicBarrier Finished All Tasks...");
}

结果:

cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier running...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished...
cyclicBarrier Finished All Tasks...

executorService.isTerminated()

ExecutorService调用shutdown()方法后,可以通过方法isTerminated()来判断任务是否完成。代码如下:

private static void executeServiceIsTerminated() {
  ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
  IntStream.range(0, NUM)
    .forEach(i -> executorService.execute(new PkslowTask("Task " + i)));
  executorService.shutdown();
  while (!executorService.isTerminated()) {
    //waiting...
  }
  System.out.println("executeServiceIsTerminated Finished All Tasks...");

}

结果:

Task 0 is running
Task 2 is running
Task 1 is running
Task 3 is running
Task 4 is running
Task 0 is completed
Task 2 is completed
Task 5 is running
Task 4 is completed
Task 7 is running
Task 3 is completed
Task 1 is completed
Task 8 is running
Task 6 is running
Task 9 is running
Task 5 is completed
Task 9 is completed
Task 7 is completed
Task 6 is completed
Task 8 is completed
executeServiceIsTerminated Finished All Tasks...

executorService.awaitTermination

executorService.awaitTermination方法会等待任务完成,并给一个超时时间,代码如下:

private static void executeServiceAwaitTermination() {
  ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
  IntStream.range(0, NUM)
    .forEach(i -> executorService.execute(new PkslowTask("Task " + i)));
  executorService.shutdown();

  try {
    if (!executorService.awaitTermination(1, TimeUnit.MINUTES)) {
      executorService.shutdownNow();
    }
  } catch (InterruptedException e) {
    throw new RuntimeException(e);
  }
  System.out.println("executeServiceAwaitTermination Finished All Tasks...");
}

结果:

Task 0 is running
Task 1 is running
Task 2 is running
Task 3 is running
Task 4 is running
Task 0 is completed
Task 5 is running
Task 1 is completed
Task 4 is completed
Task 7 is running
Task 3 is completed
Task 8 is running
Task 2 is completed
Task 9 is running
Task 6 is running
Task 5 is completed
Task 7 is completed
Task 9 is completed
Task 8 is completed
Task 6 is completed
executeServiceAwaitTermination Finished All Tasks...

executorService.invokeAll

使用invokeAll提交所有任务,代码如下:

private static void executeServiceInvokeAll() {
  ExecutorService executorService = Executors.newFixedThreadPool(THREADS);
  List<Callable<Void>> tasks = new ArrayList<>();

  IntStream.range(0, NUM)
    .forEach(i -> tasks.add(new PkslowTask("Task " + i)));

  try {
    executorService.invokeAll(tasks);
  } catch (InterruptedException e) {
    throw new RuntimeException(e);
  }

  executorService.shutdown();
  System.out.println("executeServiceInvokeAll Finished All Tasks...");
}

结果:

Task 1 is running
Task 2 is running
Task 0 is running
Task 3 is running
Task 4 is running
Task 1 is completed
Task 3 is completed
Task 0 is completed
Task 2 is completed
Task 4 is completed
Task 8 is running
Task 5 is running
Task 6 is running
Task 9 is running
Task 7 is running
Task 8 is completed
Task 5 is completed
Task 6 is completed
Task 9 is completed
Task 7 is completed
executeServiceInvokeAll Finished All Tasks...

ExecutorCompletionService

ExecutorCompletionService通过take()方法,会返回最早完成的任务,代码如下:

private static void executorCompletionService() {
  ExecutorService executorService = Executors.newFixedThreadPool(10);
  CompletionService<String> service = new ExecutorCompletionService<>(executorService);

  List<Callable<String>> callables = new ArrayList<>();
  callables.add(new DelayedCallable(2000, "2000ms"));
  callables.add(new DelayedCallable(1500, "1500ms"));
  callables.add(new DelayedCallable(6000, "6000ms"));
  callables.add(new DelayedCallable(2500, "2500ms"));
  callables.add(new DelayedCallable(300, "300ms"));
  callables.add(new DelayedCallable(3000, "3000ms"));
  callables.add(new DelayedCallable(1100, "1100ms"));
  callables.add(new DelayedCallable(100, "100ms"));
  callables.add(new DelayedCallable(100, "100ms"));
  callables.add(new DelayedCallable(100, "100ms"));

  callables.forEach(service::submit);

  for (int i = 0; i < NUM; i++) {
    try {
      Future<String> future = service.take();
      System.out.println(future.get() + " task is completed");
    } catch (InterruptedException | ExecutionException e) {
      throw new RuntimeException(e);
    }
  }

  System.out.println("executorCompletionService Finished All Tasks...");

  executorService.shutdown();
  awaitTerminationAfterShutdown(executorService);
}

这里不同任务的时长是不一样的,但会先返回最早完成的任务:

2000ms is running
2500ms is running
300ms is running
1500ms is running
6000ms is running
3000ms is running
1100ms is running
100ms is running
100ms is running
100ms is running
100ms is completed
100ms is completed
100ms task is completed
100ms task is completed
100ms is completed
100ms task is completed
300ms is completed
300ms task is completed
1100ms is completed
1100ms task is completed
1500ms is completed
1500ms task is completed
2000ms is completed
2000ms task is completed
2500ms is completed
2500ms task is completed
3000ms is completed
3000ms task is completed
6000ms is completed
6000ms task is completed
executorCompletionService Finished All Tasks...

代码

代码请看GitHub: https://github.com/LarryDpk/pkslow-samples

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/396288.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【建议收藏】深入浅出Yolo目标检测算法(含Python实现源码)

深入浅出Yolo目标检测算法&#xff08;含Python实现源码&#xff09; 文章目录深入浅出Yolo目标检测算法&#xff08;含Python实现源码&#xff09;1. One-stage & Two-stage2. Yolo详解2.1 Yolo命名2.2 端到端输入输出2.3 Yolo中的标定框2.4 Yolo网络结构2.5 Yolo的算法流…

【IoT】《天道》中音响案例的SWOT分析

在20世纪80年代初&#xff0c;SWOT最初是由美国知名管理学教授海因茨韦里克提出的。 之后这个工具就经常被用于企业的战略分析、竞争对手分析等场景。 在每年例行的公司产品规划过程中&#xff0c;我个人也经常使用这个工具。 由于涉及一些公司商业上的信息&#xff0c;下面会用…

Linux- 系统随你玩之--网络上的黑客帝国

文章目录1、前言2、TCPDump介绍2.1、问题来了&#xff1a; 所有用户都可以采用该命令吗&#xff1f;2.2、抓包原理2.3、特点2.3.1、参数化支持2.2.2、 TCP功能3、 服务器安装Tcpdump3.1、安装3.2、检查安装是否正常。4、tcpdump 命令4.1、常用功能选项4.2、输出内容5、实操5.1、…

安卓反编译入门04-对重新打包的APK进行签名

前提&#xff1a;重签的前提需要安装java环境&#xff0c;我电脑安装的地址&#xff1a;C:\Program Files\Java\重签的文件目录地址要在jdk的bin目录。进入命令行&#xff0c;执行 cd/d C:\Program Files\Java\jdk1.8.0_181\bin(注意&#xff0c;由于这个文件C:\Program Files要…

Git 分支操作【解决分支冲突问题】

1. 什么是分支 在版本控制过程中&#xff0c;同时推进多个任务&#xff0c;为每个任务&#xff0c;我们就可以创建每个任务的单独分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来&#xff0c;开发自己分支的时候&#xff0c;不会影响主线分支的运行。对于初学…

Redhat7.6安装weblogic10.3.6(超详细,有图文)

一、环境 linux版本&#xff1a;Redhat 7.6 weblogic版本:WLS10.3.6 jdk版本&#xff1a;jdk1.8.0 下载网址&#xff1a;https://www.oracle.com/technetwork/middleware/weblogic/downloads/index.html 1.安装vsftpd服务&#xff0c;将部署环境使用JDK文件和wls服务文件…

【鸿蒙应用ArkTS开发系列】- 页面跳转及传参

先看下效果图 大致实现的功能点&#xff1a; 从Indext页面跳转到Second页面&#xff0c;传递两个参数&#xff0c;一个字符串&#xff0c;一个数量&#xff1b;Second获取Index页面传递的数据&#xff1b;Second页面点击返回弹窗&#xff1b;Second页面返回携带参数数据&#…

API接口实战演练,参考示例说明

onebound.1688.item_get 公共参数 名称类型必须描述keyString是 调用key&#xff08;必须以GET方式拼接在URL中&#xff09; 注册Key和secret测试 secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_se…

OpenStack手动分布式部署Nova【Queens版】

目录 Nove简介&#xff1a; 1、登录数据库配置&#xff08;在controller执行&#xff09; 1.1登录数据库 1.2数据库里创建nova-api 1.3数据库登录授权 1.4创建nova用户 1.5添加admin用户为nova用户 1.6创建nova服务端点 1.7创建compute API 服务端点 1.8创建一个placement服务…

C++源码pcl1.13.0库编译环境搭建及配置

Pcl github库https://github.com/PointCloudLibrary/pcl官网地址https://pointclouds.org/Pcl exe的下载地址&#xff0c;各个版本&#xff0c;以及各版本对应的源码https://github.com/PointCloudLibrary/pcl/releases源码需要编译&#xff0c;编译之前安装AllInOne的exe程序&…

【数据结构】单链表:头部操作我很行,插入也不用增容!!!

单链表 文章目录单链表1.链表1.1链表的概念和结构1.2链表的分类2.单链表的模拟实现2.1单链表的打印2.2单链表的尾插2.3单链表的头插2.4单链表的尾删2.5单链表的头删2.6单链表的查找2.7单链表的中间插入(在结点前插入)2.8单链表的中间删除(删除该结点)2.9单链表的中间插入(在结点…

如何学好市场营销?

首先&#xff0c;要学好市场营销学肯定是需要看书的&#xff0c;可以多看些类似《经理人参阅&#xff1a;市场营销》一类的经典书籍&#xff0c;虽然比普通书贵些但是值。注意该书只有其官网有&#xff0c;请自行百度。看书在于精而不在于多&#xff0c;个人认为要学好市场营销…

软考高级备考哪一个类型好些?

软考高级是比中级和初级难&#xff0c;科目就要考三科&#xff0c;选择题基础知识简答题案例分析写作论文 软考高级科目有&#xff1a;信息系统项目管理师、系统分析师、系统架构设计师、网络规划师、系统规划与管理师。如下&#xff1a; 软考高级中高项信息系统项目管理师师比…

Qt 贴图实现方向控制盘

一、效果走一波 二、使用贴图进行不规则按钮的设计与开发 开发环境描述&#xff1a;QtCreator Qt Desinger &#xff08;1&#xff09;首先准备待贴的图片 ​ 图片的切片大小必须一样&#xff0c;背景为透明的&#xff1b;将待贴的所有图片都切下来&#xff0c;文件标明名称…

移动App性能测试包含哪些内容?App性能测试工具有哪些?

随着互联网高科技的蓬勃发展&#xff0c;移动app的的需求量和供给量都较大。但一款好app的成功上线以及为用户带来高效体验&#xff0c;性能测试起着关键性的作用。性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试&#xff0…

【STM32存储器映射-寄存器基地址-偏移】

前言 在学习STM32的时候&#xff0c;我们看到很多的寄存器编程&#xff0c; 比方说LED灯&#xff1a; //GPIOB.5端口输出高电平GPIOB->ODR|1<<5; //PB.5 输出高GPIOE->ODR|1<<5; //PE.5输出高 //GPIOB端口全部输出高电平*(unsigned int*)(0x4001 …

从深分页查询到覆盖索引

最近看到一道面试题&#xff0c;如何优化深分页查询 最简单的例子是 select * from web_bill_main limit 30000,10;分页达到30000行&#xff0c;需要把前面29999行都过滤掉&#xff0c;才能找到这10条数据 所以整体时间花了80ms(工具显示时间) 我当时的第一反应是&#xff0…

python Django的admin后台建设

什么是admin管理后台 1、django提供了完善的后台管理数据库的接口&#xff0c;可供开发过程中调用和测试使用2、django 会搜集所有已注册的模型类&#xff0c;为这些模型类提供数据管理界面&#xff0c;供开发者使用admin配置步骤1、创建后台管理账号-该账号为管理后台最高权限…

193、【动态规划】AcWing —— 291. 蒙德里安的梦想:状压dp详细解析(C++版本)

题目描述 原题链接&#xff1a;291. 蒙德里安的梦想 解题思路 &#xff08;1&#xff09;状态压缩dp先导知识 状态压缩会用二进制位来存储状态信息&#xff0c;在状态计算时&#xff0c;将整数转化为二进制爹形式进行计算。 可表示的状态就是 2n2^n2n 个。 &#xff08;2&…

python 列表删除多个元素

文章目录一. 删除列表多个元素方法1 使用枚举&#xff1a;2. 使用python中List.pop()方法3. 使用python中List.remove()方法4. 注意二. 使用双指针法删除列表多个元素1. 问题描述&#xff1a;2. 解决方法&#xff1a;3. 代码如下&#xff1a;三. 总结四. 相关链接一. 删除列表多…