Java 异步编程——多线程都执行完再继续执行主流程(使用 CountDownLatch 类或调用 ExecutorService 的 invokeAll() 方法)

Java多种方法实现等待所有子线程完成再继续执行 简介 在现实世界中,我们常常需要等待其它任务完成,才能继续执行下一步。Java实现等待子线程完成再继续执行的方式很多。我们来一一查看一下。 Thread的join方法 该方法是Thread提供的方法,调用join()时,会阻塞主线程,等该Thread完成才会继续执行,代码如下: private static void threadJoin() { List<Thread> threads = new ArrayList<>(); for (int i = 0; i < 阅读详情
AI摘要

本文介绍了Java异步编程中让多线程都执行完再继续执行主流程的两种方法,即使用CountDownLatch类和调用ExecutorService的invokeAll()方法。CountDownLatch适用于Runnable任务,可灵活控制;invokeAll()适用于Callable任务,能简单等待任务完成并收集结果。还阐述了CountDownLatch的原理、使用场景及示例。


在使用 ThreadPoolExecutor 执行多个任务时,有时需要等待所有任务完成后再执行下一步操作。可以使用 ExecutorService 的 invokeAll() 方法或者结合 CountDownLatch 来实现这一功能。

  1. invokeAll() 方法:
    • 适用于 Callable 任务,简单明了地等待所有任务完成,并收集结果。
  2. CountDownLatch:
    • 适用于 Runnable 任务,提供了更灵活的控制,可以在任务执行过程中进行其他操作。

两种方式都能有效地保证在所有线程完成任务后再执行后续操作,选择哪种方式取决于具体的使用场景和任务类型。

CountDownLatch

CountDownLatch 是 Java 并发包中的一个同步辅助工具类,允许一个或多个线程等待直到一组操作完成。它可以用于实现任务的协调,确保某些线程在继续执行之前等待其他线程完成任务。

CountDownLatch 是一个计数的闭锁,作用与 CyclicBarrier 有点儿相似。CountDownLatch 是通过一个计数器来实现的,计数器的初始值为任务的数量。每当一个线程完成了一个任务后,计数器的值就会减1。当计数器值到达0时,它表示多线程已经完成了所有任务,然后就可以恢复等待的线程继续执行了。

工作原理:

  • 初始化时设置计数器的值为需要等待的线程任务数量。
  • 每当一个任务完成任务时,调用 countDown() 方法将计数器减 1。
  • 当计数器的值达到 0 时,所有等待的线程将被唤醒,继续执行。

使用场景

CountDownLatch 常用于以下场景:

  • 在所有线程完成某些子任务之前,不让主线程继续执行。
  • 等待多个线程执行完毕后再执行下一步操作。

示例:多个线程完成任务后主线程继续执行

import java.util.concurrent.CountDownLatch;

class MyRunnable implements Runnable {
    private final CountDownLatch latch;
    private final int taskId;

    public MyRunnable(CountDownLatch latch, int taskId) {
        this.latch = latch;
        this.taskId = taskId;
    }

    @Override
    public void run() {
        try {
            // 模拟任务执行
            System.out.println("Task " + taskId + " is running in thread: " + Thread.currentThread().getName());
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println("Task " + taskId + " completed.");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 每执行完一个任务后,CountDownLatch 计数减一
            latch.countDown(); 
        }
    }
}

public class ThreadPoolExecutorCountDownLatchExample {
    public static void main(String[] args) {
        // 需要执行的任务数量
        int numberOfTasks = 10;
        // 初始化 CountDownLatch
        CountDownLatch latch = new CountDownLatch(numberOfTasks);
        ExecutorService executor = Executors.newFixedThreadPool(4);

        // 创建并提交任务
        for (int i = 1; i <= numberOfTasks; i++) {
            executor.submit(new MyRunnable(latch, i));
        }

        try {
            // 主线程等待所有任务完成
            latch.await(); 
            System.out.println("All tasks are completed. Main thread can continue...");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            executor.shutdown(); // Shutdown the executor
        }
    }
}

1、首先初始化 CountDownLatch 的计数器初始值为任务数量。

2、在任务 run 方法结束时调用 latch.countDown(),操作计数器减一。即每完成一个任务,CountDownLatch 的计数器减一。

3、主线程调用 latch.await(),等待计数器的值变为 0,在所有任务完成之前,主线程会被阻塞。一旦所有任务执行完,计数器减为 0,主线程将继续执行并打印消息。

使用 invokeAll() 方法

invokeAll 方法会阻塞当前线程,直到所有提交的任务完成,并返回一个包含每个任务结果的列表。此方法适用于 Callable 任务。

示例代码

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

class MyCallable implements Callable<Integer> {
    private final int taskId;

    public MyCallable(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public Integer call() throws Exception {
        // 模拟任务执行
        System.out.println("Task " + taskId + " is running in thread: " + Thread.currentThread().getName());
        Thread.sleep((long) (Math.random() * 1000));
        System.out.println("Task " + taskId + " completed.");
        // 返回任务结果
        return taskId;
    }
}

public class ThreadPoolExecutorInvokeAllExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        List<Callable<Integer>> tasks = new ArrayList<>();

        // 创建并提交任务
        for (int i = 1; i <= 10; i++) {
            tasks.add(new MyCallable(i));
        }

        try {
            // 调用所有任务并等待其完成
            List<Future<Integer>> results = executor.invokeAll(tasks);
            for (Future<Integer> result : results) {
                // 获取任务执行结果
                System.out.println("Result: " + result.get()); 
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown(); // Shutdown the executor
        }

        System.out.println("All tasks are completed. Main thread can continue...");
    }
}
【Java】多线程系列(三)之阻塞线程的多种方法 前言:在某些应用场景下,我们可能需要等待某个线程执行完毕,然后才能进行后续的操作。 例如,当你在计算利用多线程执行几个比较耗时的任务的时候,主线程需要利用这几个线程计算的结果,才能进行后续的操作。那么我们其实就需要等待所有线程执行完毕。这里,介绍几个常用的方法线程执行单次的场景下1,利用Thread类的join()方法package concurrent;import java.util.Array 阅读详情

相关推荐

codesys【modbusRTU】主站

【代码】modbusRTU【codesys】

cfqq1989的博客 4375

多线程:Java里的所有线程都全部执行完毕后,代码再往下继续执行的控制方法(CountDownLatch类的用法示例)

在Java的多线程中,有的时候我们需要等某些多线程的方法全部都执行完毕后,才继续往下执行。这个该怎么控制呢?用CountDownLatch类。这个类是java.util.concurrent包里面,也即是Java的并发工具包,这个包里面有很多多线程的工具类,在多线程编程中很有用。 下面就是一个CountDownLatch类的一个用法。比如我们有五个人(五个线程),他们都赶往同一目的地,但是我们不知...

weixin_39448458的博客 8704

RPA机器人技术原理初探

RPA初步

曲折旅程,艰难人生 2138

Java 多线程,等线程里面东西都执行完成之后,才继续往下走

java

一天不写代码难受的博客 1696

ESP32驱动TFT屏幕实战:LVGL与TFT_eSPI完美结合

本文详细介绍了如何在ESP32上结合TFT_eSPI驱动库与LVGL图形库,实现高效、流畅的嵌入式GUI开发。内容涵盖硬件连接、软件环境搭建、库配置、LVGL移植、界面创建及性能优化等全流程实战指南,帮助开发者快速构建低成本、高性能的交互式显示应用。

weixin_29206669的博客 200

Python爬虫实战:5分钟搞定微信公众号文章阅读数、点赞数抓取(附完整代码)

本文详细介绍了如何通过Python爬虫技术自动化抓取微信公众号文章的阅读数和点赞数。文章从数据源分析入手,分步讲解了获取文章列表与提取单篇统计数据的完整流程,并提供了应对平台风控的策略与工程化整合方案,帮助开发者高效、合规地完成数据采集任务。

ansible6ops的博客 1337

在Java中如何确保在多线程情况下,所有线程都完成再继续执行任务?

在多线程环境下,需要保证线程安全,避免出现线程竞争和线程之间的互相干扰。在以上示例代码中,当每个 SQL 查询任务执行完毕后都将 CountDownLatch 计数器减 1,当计数器减为 0 时,主线程的 await() 方法返回,程序继续执行后面的逻辑,汇总所有 SQL 查询结果并进行处理。在主线程中,调用 CountDownLatch 的 await() 方法在所有 SQL 查询任务执行完成前阻塞线程,直到计数器减为 0 时,所有任务都已经执行完成可以继续往下执行,此时可以对查询结果进行汇总处理。

weixin_43394692的博客 6847

实战指南:在UE5中高效集成Entt(ECS)框架

本文提供了一份在虚幻引擎5中高效集成Entt ECS框架的实战指南。针对UE5项目在处理大规模动态实体时的性能瓶颈,详细讲解了如何通过数据驱动的ECS架构进行优化。内容包括前期环境准备、核心构建步骤、创建首个ECS子系统以及与UE原生系统的数据同步技巧,旨在帮助开发者快速掌握集成方法,提升游戏逻辑的执行效率。

weixin_29002209的博客 158

JAVA多线程下的同步问题-等所有线程执行完在执行下面的操作

JAVA同步工具类CountDownLatch的用法 提示:在我们进行JAVA多线程编程时,有时我们想要等到所有新开辟的线程执行完毕后再执行下面的操作,又或者是需要等到异步操作的结果。那么,此时我们就需要对当前的“主线程”进行阻塞。Java的同步工具类CountDownLatch给我们提供了一个不错的解决方案。 文章目录JAVA同步工具类CountDownLatch的用法一、概念二、工具类常用方法1.await()2.countDown()三、完整例子总结在实时系统中的使用场景 一、概念 CountD

myQNUMNINE的博客 4009

unitree-G1外接 USB 麦克风完整配置指南

首先,将type-c麦克风插入G1机器人的USB口后,记录下USB麦克风的卡号(card)和设备号(device),通常显示为 card 1: Device [USB Audio Device]

m0_47999117的博客 600

PCL 将对象模板与点云对齐【2025最新版】

PCL模版匹配算法的使用案例,博客长期更新,本文最近更新时间为:2025年1月18日。

点云侠的博客 5379

for循环内线程池并发执行任务,等到子线程全部处理完任务,主线程在执行java的实现方式

当计数器减为 0 时,所有子线程的任务都已经执行完毕,主线程可以执行后续代码。在主线程中,调用 CountDownLatch.await() 方法阻塞等待所有子线程的任务执行完毕,直到计数器减为 0 才继续执行后续代码。请注意,在使用自定义线程池时,需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。请注意,在实际应用中,您还需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。请注意,在使用以上方法时,仍然需要考虑线程安全、并发访问等问题,并在代码中正确处理异常。

启迪思维,精进技术 6826

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

ExecutorService等待线程完成后优雅结束

1.概述 该ExecutorService框架可以很容易地在处理多线程任务。我们将举例说明我们等待线程完成执行的一些场景。 此外,我们将展示如何正常关闭ExecutorService并等待已经运行的线程完成其执行。 2.Executor关闭后 使用Executor时,我们可以通过调用shutdown()或shutdownNow()方法将其关闭。虽然,它不会等到所有线程都停止执行。 等待现有线程完成...

淡定_蜗牛的博客 1万+

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Java异步判断线程池所有任务是否执行完成的方法

本文详细介绍了Java异步判断线程池所有任务是否执行完成的方法,分别介绍了使用ExecutorService和CountDownLatch的方法示例、使用ExecutorService的invokeAll方法和Future列表的方法示例、使用ExecutorService来异步执行多个Callable任务方法示例三个例子,并分别给出了详细的代码示例,直观清晰、一目了然。

m0_72958694的博客 1278

Java并行执行任务的几种方案

背景 最近在排查生产环境问题,发现商品详情接口时不时会报RPC调用超时,检查代码发现接口里面查询活动耗时比较长,都是串行执行的,仔细查看发现完全可以改成并行去执行,缩短接口查询耗时。 比如我们的商品详情接口,需要展示立减、阶梯满减、团购等活动标签。需要查询三次不同的活动信息,再组装活动标签信息。如果每次查询耗时1s,按照串行的方式去调用,整个接口下来至少需要3s,整个耗时,对于我们来讲是无法接受...

weixin_33851429的博客 8680

Java中线程等待(同步)的五种方法

在面试时,经常会有面试官问道,如何将

1万+

java关于多线程并发和异步操作由浅入深

目录前言一、初识多线程多线程最基本的两种实现方式**- 方式一:- 方式二:多线程优点:二、匿名函数实现无返回值的多线程异步调用三、CompletableFuture实现多线程异步调用无返回值的异步调用有返回值的异步调用四、四种线程池的使用1.newFixedThreadPool定长线程池2.CachedThreadPool可缓存线程池3.newSingleThreadExecutor单线程化线程池4. newScheduledThreadPool周期性线程池无返回值的延时线程示例:有返回值的延时线程示例:

西凉的悲伤博客 8531

【架构之路】java线程池执行过程

每个子线程在执行完毕后调用latch.countDown(),表示它已完成。主线程则调用latch.await(),该方法会阻塞直到计数器减至0,即所有子线程都已调用过countDown()。在这个示例中,我们创建了一个包含五个Callable任务的列表,并使用executor.invokeAll(tasks)一次性提交所有任务。在Java中确保主线程在五个子线程全部执行完成后退出,您可以使用ExecutorService提供的invokeAll()方法或CountDownLatch类来同步线程执行。

qq_31532979的贺公子之数据科学与艺术博客,致力于科技向善,拥抱开源,要用技术的影响力来领导团队,而不是威权和职位! 501

Java并发执行任务的几种方式

背景 在编写业务代码时经常遇到并发执行多个任务的需求,因为串行执行太慢,会影响业务代码性能。特别对于直接面向普通用户的业务来说用户体验至关重要,保证用户体验重要的一点是要“快”。业务代码中经常需要调用其它业务接口或者同时从多个数据源取数据再处理等,这种情况下势必要走网络请求,网络消耗必不可少,最好的情况是毫秒级别,一般情况下是几十毫秒级别,甚至几百毫秒,TimeoutException恐怕大家并...

码到功成 1万+

java异步判断线程池所有任务是否执行完

1.使用ExecutorService和CountDownLatch的方法示例 在Java中,当我们使用线程池(如ExecutorService)来执行异步任务时,常常需要知道所有任务是否都已经完成。ExecutorService接口提供了几种方式来处理这种情况,但最常用的是shutdown()和awaitTerminat...

weixin_31894867的博客 212

Java ExecutorService 多线程实践(一)

需要实现一个多线程并发的业务场景,启动若干子线程,最后要所有子线程运行结束才结束。(类似 .NET 里的 Task WaitAll ) Java 中的 ExecutorService 多线程编程模型提供这样一个机制,通过代码来介绍一下。

Lullaby's Blog 5461

java请求并行方案_Java并行执行任务的几种方案

最近在排查生产环境问题,发现商品详情接口时不时会报RPC调用超时,检查代码发现接口里面查询活动耗时比较长,都是串行执行的,仔细查看发现完全可以改成并行去执行,缩短接口查询耗时。 比如我们的商品详情接口,需要展示立减、阶梯满减、团购等活动标签。需要查询三次不同的活动信息,再组装活动标签信息。如果每次查询耗时1s,按照串行的方式去调用,整个接口下来至少需要3s,整个耗时,对于我们来讲是无法接受的。其...

weixin_35625530的博客 973

多线程同步与任务完成等待机制总结

在多线程编程中,合理的同步机制能够有效地协调多个线程之间的执行顺序,确保任务按照预期执行。常见的同步机制包括和Phaser。接下来,我们将通过具体场景加伪代码示例来介绍这些同步工具的应用。在 Java 中,不同的同步工具有不同的适用场景。根据项目的具体需求,选择合适的同步机制能提高并发性能并避免线程安全问题。:用于等待所有线程完成,适合任务依赖的场景。:适用于多线程到达某个同步点后一起继续执行,常用于周期性任务。:适用于处理异步任务,能灵活地组合任务。:适用于确保一组任务完成后执行汇总操作。

DolphinHome的博客 1597
上一篇: Java 异步编程——常用线程池 ThreadPoolExecutor
下一篇: Java 异步编程——异步处理并发任务的执行结果(CompletionService)
ShareBeHappy_Qin
博客等级 码龄9年 2321粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值