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

2023-05-16

简介

在现实世界中,我们常常需要等待其它任务完成,才能继续执行下一步。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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 自定义FailureAnalyzer

    目录 介绍 代码示例 介绍 FailureAnalyzer是一种很好的方式在启动时拦截异常并将其转换为易读的消息 xff0c 并将其包含在FailureAnalysis中 Spring Boot为应用程序上下文相关异常 JSR 303验证等
  • 自动配置故障排除

    目录 官网文档 71 2 Troubleshoot auto configuration 翻译 71 2 自动配置故障排除 官网文档 71 2 Troubleshoot auto configuration The Spring Boot
  • 在环境或应用程序上下文启动之前对其进行自定义

    目录 官网文档 71 3 Customize the Environment or ApplicationContext before it starts 翻译 71 3 在环境或应用程序上下文启动之前对其进行自定义 官网文档 71 3 C
  • 构建ApplicationContext层次结构(添加父上下文或根上下文)

    目录 官网文档 71 4 Build an ApplicationContext hierarchy adding a parent or root context 翻译 71 4 构建ApplicationContext层次结构 xff0
  • 创建非Web应用程序

    目录 官方文档 71 5 Create a non web application 翻译 71 5 创建非Web应用程序 官方文档 71 5 Create a non web application Not all Spring appli
  • Customizing the Banner

    自定义方式 1 设置banner txt文件 默认读取根路径 xff0c 也可以通过banner location属性指定文件位置 xff0c 并且可以通过banner charset 默认是UTF 8 属性设置txt文件编码 在banne
  • isAssignableFrom方法浅析

    源码 Determines if the class or interface represented by this 64 code Class object is either the same as or is a superclas
  • @SuppressWarnings("serial")

    比如有个类实现了java io Serialize接口 xff1a package com onede4 test public class TestSerial implements java io Serializable 如果代码仅仅
  • angularJs中将字符串转换为HTML格式

    首先定义一个filter xff1a filter 39 to trusted 39 39 sce 39 function sce return function text return sce trustAsHtml text 2 htm
  • 如何在IDEA启动多个Spring Boot工程实例

    目录 只需要三步走即可 在IDEA上点击Application右边的下三角 弹出选项后 xff0c 点击Edit Configuration 打开配置后 xff0c 将默认的Single instance only 单实例 的钩去掉 通过修
  • springboot学习记录一

    概述 Spring Boot可以轻松创建独立的 xff0c 生产级的基于Spring的应用程序 xff0c 您可以 只要运行 我们对Spring平台和第三方库采取了自以为是 武断 的观点 xff0c 因此您可以最少的手忙脚乱 慌乱 开始 大
  • Java8 如何正确使用 Optional

    引用 http www importnew com 26066 html Optional是Java8提供的为了解决null安全问题的一个API 善用Optional可以使我们代码中很多繁琐 丑陋的设计变得十分优雅 这篇文章是建立在你对Op
  • git清除本地账户

    删除保存在本地的git账户 git credential manager uninstall 缓存账户 git config global credential helper wincred
  • 服务注册与发现eureka

    目录 eureka server pom xml文件添加依赖 启动类添加注解 64 EnableEurekaServer appication yml配置文件 访问界面 eureka client pom xml文件添加依赖 启动类添加注解
  • 服务消费者RestTemplate+Ribbon

    目录 简介 pom xml添加依赖 通过 64 LoadBalanced注解表明这个restRemplate开启负载均衡的功能 这样 restTemplate访问接口就可以实现负载均衡功能了 简介 spring cloud有两种服务调用方式
  • 服务消费者Feign

    Feign简介 Feign是一个声明式的伪Http客户端 xff0c 它使得写Http客户端变得更简单 使用Feign xff0c 只需要创建一个接口并注解 它具有可插拔的注解特性 xff0c 可使用Feign 注解和JAX RS注解 Fe
  • 熔断器Hystrix

    目录 概述 在ribbon使用断路器 断路器简介 添加依赖 启动类添加注解 64 EnableHystrix 方法上添加 64 HystrixCommand 关闭service hi服务 Feign中使用断路器 开启断路器功能 修改 64
  • Hystrix Dashboard (断路器:Hystrix 仪表盘)

    目录 pom xml添加依赖 启动类添加 64 EnableHystrixDashboard注解 浏览器访问 pom xml添加依赖 lt dependency gt lt groupId gt org springframework bo
  • nexus3私服搭建

    应用场景 maven库分为本地仓库和远程仓库 包括私服和中央仓库 xff09 公司自己设立 xff0c 只为公司内部共享使用 xff0c 同时减少外部访问和下载频率等 使用Nexus搭建私服 下载 官网链接 xff1a https www
  • Java多种方法实现等待所有子线程完成再继续执行

    简介 在现实世界中 xff0c 我们常常需要等待其它任务完成 xff0c 才能继续执行下一步 Java实现等待子线程完成再继续执行的方式很多 我们来一一查看一下 Thread的join方法 该方法是Thread提供的方法 xff0c 调用j