java 实现等待多个子任务完成后,继续执行主流程

字节揽雪客
• 阅读 1892

在Java中,可以使用CountDownLatch或者CompletableFuture来等待多个子任务完成后,继续执行主流程。

一、基本实现

1、使用CountDownLatch的实现

import java.util.concurrent.CountDownLatch;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int taskNum = 5;
        CountDownLatch countDownLatch = new CountDownLatch(taskNum);

        for (int i = 0; i < taskNum; i++) {
            new Thread(() -> {
                try {
                    // 子任务的执行代码
                    // ...

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    // 完成一个子任务,计数器减1
                    countDownLatch.countDown();
                }
            }).start();
        }

        // 等待所有子任务完成
        countDownLatch.await();

        // 所有子任务完成后,继续执行主流程
        // ...
    }
}

在上面的CountDownLatch的示例代码中,如果子任务执行过程中抛出异常,主线程并不能立即感知,因此需要在子任务中进行异常处理,否则主线程可能会一直等待。

2、使用CompletableFuture实现

1)带返回值

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        List<CompletableFuture<String>> futures = Stream.of(1, 2, 3, 4, 5)
                .map(i -> CompletableFuture.supplyAsync(() -> {
                    try {
                        // 子任务的执行代码,返回一个字符串结果
                        // ...

                    } catch (Exception e) {
                        // 处理子任务执行过程中的异常
                        e.printStackTrace();
                        return null; // 返回null表示子任务执行失败
                    }

                    return "Result " + i;
                }))
                .collect(Collectors.toList());

        // 等待所有子任务完成并获取结果
        List<String> results = futures.stream()
                .map(CompletableFuture::join)
                .filter(result -> result != null)
                .collect(Collectors.toList());

        // 所有子任务完成后,继续执行主流程
        // ...
    }
}

2)不带返回值

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        List<CompletableFuture<Void>> futures = Stream.of(1, 2, 3, 4, 5)
                .map(i -> CompletableFuture.runAsync(() -> {
                     try {
                        // 子任务的执行代码,返回一个字符串结果
                        // ...

                    } catch (Exception e) {
                        // 处理子任务执行过程中的异常
                        e.printStackTrace();
                       // ...
                    }
                }))
                .collect(Collectors.toList());

        // 等待所有子任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        // 所有子任务完成后,继续执行主流程
        // ...
    }
}

在上面的CompletableFuture示例代码中,如果子任务执行过程中抛出异常,主线程并不能立即感知,因此需要在子任务中进行异常处理,否则主线程可能会一直等待。

二、CompletableFuture超时处理

CompletableFuture是一个基于Future和CompletionStage的异步编程框架,可以让开发者通过简单的API来组合多个异步任务,实现更加灵活和高效的异步编程方式。CompletableFuture还支持异常处理、超时等特性,能够帮助开发者更好地处理复杂的异步场景。

1、代码实现

import java.time.Duration;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Duration timeout = Duration.ofSeconds(5);
        List<CompletableFuture<String>> futures = Stream.of(1, 2, 3, 4, 5)
                .map(i -> CompletableFuture.supplyAsync(() -> {
                    try {
                        // 子任务的执行代码,返回一个字符串结果
                        // ...

                    } catch (Exception e) {
                        // 处理子任务执行过程中的异常
                        e.printStackTrace();
                        return null; // 返回null表示子任务执行失败
                    }

                    return "Result " + i;
                }))
                .collect(Collectors.toList());

        // 等待所有子任务完成并获取结果
        List<String> results = futures.stream()
                .map(future -> {
                    try {
                        return future.get(timeout.toMillis(), java.util.concurrent.TimeUnit.MILLISECONDS);
                    } catch (InterruptedException | ExecutionException | TimeoutException e) {
                        // 处理子任务执行过程中的异常或超时
                        e.printStackTrace();
                        future.cancel(true); // 取消未完成的子任务
                        return null; // 返回null表示子任务执行失败
                    }
                })
                .filter(result -> result != null)
                .collect(Collectors.toList());

        // 所有子任务完成后,继续执行主流程
        // ...
    }
}

2、Stream.of(1, 2, 3, 4, 5) 是必须得么?是否可以替换?

在上面的示例代码中,Stream.of(1, 2, 3, 4, 5)这行代码并不是必须的,它只是为了演示使用StreamAPI创建CompletableFuture对象的一种方式。在实际开发中,你可能会有不同的方式来创建CompletableFuture对象,例如通过调用其他方法、读取文件、调用远程接口等方式。

Stream.of()方法是用来创建一个由指定元素组成的顺序流的。在这里,我们使用Stream.of(1, 2, 3, 4, 5)来创建一个包含整数1到5的顺序流,然后对这个流使用map()方法来将每个整数转换为一个CompletableFuture对象,最终通过collect()方法将所有CompletableFuture对象收集到一个列表中。

如果你有其他的方式来创建CompletableFuture对象,可以根据实际情况使用不同的方法来创建,而不必一定使用Stream.of()方法。CompletableFuture对象可以通过多种方式创建,例如使用CompletableFuture.supplyAsync()方法创建、使用CompletableFuture.runAsync()方法创建、使用CompletableFuture.completedFuture()方法创建等等,具体取决于你的业务需求。

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
4年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这