CompletableFuture多任务异步,获取返回值,汇总结果

线程池异步的基础知识

详情见:https://blog.csdn.net/sinat_32502451/article/details/133039624

线程池执行多任务,获取返回值

线程池的 submit()方法,可以提交任务,并返回 Future接口。
而 future.get(),可以获取到任务的结果,但是get()方法会阻塞,阻塞时间过长,会占用过多的系统资源。
因此在使用时,一般都会用 get(long timeout, TimeUnit unit) 设置超时时间。

//该线程池仅用于示例,实际建议使用自定义的线程池
ExecutorService executor = Executors.newCachedThreadPool();
Future<String> future = executor.submit(() -> "task1");
//阻塞,获取返回值,2秒超时
String result = future.get(2, TimeUnit.SECONDS);

不过,get(long timeout, TimeUnit unit) 比较适合设置单个任务的超时时间,在多任务的情况下,哪怕设置了超时时间,阻塞的时间也会特别长。
比如,有5个任务同时执行,每个任务设置2s的超时时间,在极端情况下,这些任务全部阻塞并超时,那总共要耗费的时间,可能会达到10s,这明显是不能接受的。
如果超时时间设置得太小,又可能出现频繁超时。在多任务获取返回值的场景,更适合使用 CompletableFuture。

CompletableFuture基础知识

详情见: https://blog.csdn.net/sinat_32502451/article/details/132819472

CompletableFuture多任务异步

CompletableFuture多任务异步,不需要返回值的话,主要使用 allOf()。

  • allOf():就是将多个任务汇总成一个任务,所有任务都完成时触发。allOf()可以配合get()一起使用。
public static void allOfTest() throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        CompletableFuture<Void> cf1 = CompletableFuture.runAsync(
                () -> System.out.println("cf1 ok."), executorService);
        CompletableFuture<Void> cf2 = CompletableFuture.runAsync(
                () -> System.out.println("cf2 ok."), executorService);
        
        //将两个任务组装成一个新的任务,总共的超时时间为2s
        CompletableFuture.allOf(cf1, cf2).get(2, TimeUnit.SECONDS);
    }

CompletableFuture获取返回值

只有一个任务时,CompletableFuture的使用,跟线程池异步有点类似。
主要用到 CompletableFuture.supplyAsync(): 异步处理任务,有返回值。

     public static void supplyAsyncGet()  {
        //该线程池仅用于示例,实际建议使用自定义的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()
                -> runTask(), executorService);

        String result = null;
        try {
            //获取返回值,2秒超时
            result = completableFuture.get(2, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.error("completableFuture.get error.", e);
        }
        logger.info("result:"+result);
    }

    private static String runTask() {
        try {
            //任务耗时。可以分别设置1000和3000,看未超时和超时的不同结果。
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            logger.error("runTask error.", e);
        }
        return "taskResult";
    }

CompletableFuture多任务异步,获取返回值,汇总结果

有几个方法比较关键:

  • supplyAsync(): 异步处理任务,有返回值
  • whenComplete():任务完成后触发,该方法有返回值。还有两个参数,第一个参数是任务的返回值,第二个参数是异常。
  • allOf():就是所有任务都完成时触发。allOf()可以配合get()一起使用。

示例如下:

    /**
     *  异步,多任务。汇总返回值
     */
    public static void allOfGet()  {
        //该线程池仅用于示例,实际建议使用自定义的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();

        //线程安全的list,适合写多读少的场景
        List<String> resultList = Collections.synchronizedList(new ArrayList<>(50));
        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(
                () -> runTask("result1", 1000), executorService)
                .whenComplete((result, throwable) -> {
                    //任务完成时执行。用list存放任务的返回值
                    if (result != null) {
                        resultList.add(result);
                    }
                    //触发异常
                    if (throwable != null) {
                        logger.error("completableFuture1  error:{}", throwable);
                    }
                });

        CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(
                () -> runTask("result2", 1500), executorService)
                .whenComplete((result, throwable) ->{
                    if (result != null) {
                        resultList.add(result);
                    }
                    if (throwable != null) {
                        logger.error("completableFuture2  error:{}", throwable);
                    }

                });

        List<CompletableFuture<String>> futureList = new ArrayList<>();
        futureList.add(completableFuture1);
        futureList.add(completableFuture2);

        try  {
            //多个任务
            CompletableFuture[] futureArray = futureList.toArray(new CompletableFuture[0]);
            //将多个任务,汇总成一个任务,总共耗时不超时2秒
            CompletableFuture.allOf(futureArray).get(2, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.error("CompletableFuture.allOf Exception error.", e);
        }
        List<String> list = new ArrayList<>(resultList);

        list.forEach(System.out::println);
    }


    private static String runTask(String result, int millis) {
        try {
            //此处忽略实际的逻辑,用sleep代替
            //任务耗时。可以分别设置1000和3000,看未超时和超时的不同结果。
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            logger.error("supplyAsyncGet error.");
        }
        return result;
    }

相关资料:

https://blog.csdn.net/sinat_32502451/article/details/132819472

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
虽然CompletableFuture可以用来执行异步任务并返回结果,但是它也可以用来执行异步任务但不返回结果。在这种情况下,我们可以使用CompletableFuture的thenRun()方法或thenAccept()方法来处理异步任务的执行结果。 例如,下面的代码演示了如何使用CompletableFuture执行一个简单的异步任务,但不返回任何结果: ``` CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 执行异步任务,不返回结果 System.out.println("Async task executed."); }); future.thenRun(() -> { // 异步任务执行完成后,执行回调函数 System.out.println("Async task completed."); }); ``` 在上面的代码中,我们使用CompletableFuture.runAsync方法来执行一个简单的异步任务,该任务不返回任何结果,只是在控制台上输出一条信息。然后,我们使用CompletableFuture的thenRun()方法来注册一个回调函数,在异步任务执行完成后执行该回调函数。在这个例子中,我们只是在控制台上输出一条信息"Async task completed.",表示异步任务已经完成。需要注意的是,这个回调函数并不会接收异步任务的计算结果,因为异步任务并没有返回任何结果。 除了thenRun()方法外,CompletableFuture还提供了thenAccept()方法,它可以用来处理异步任务的计算结果。与thenRun()方法不同的是,thenAccept()方法会接收异步任务的计算结果作为参数,并进行一些处理。例如,下面的代码演示了如何使用thenAccept()方法来处理异步任务的计算结果: ``` CompletableFuture.supplyAsync(() -> { // 执行异步任务,并返回一个结果 return "Hello, world!"; }).thenAccept(result -> { // 处理异步任务的结果 System.out.println("Async task completed with result: " + result); }); ``` 在上面的代码中,我们使用CompletableFuture.supplyAsync()方法来执行一个异步任务,并返回一个字符串"Hello, world!"作为计算结果。然后,我们使用thenAccept()方法来处理异步任务的结果,将其输出到控制台上。需要注意的是,thenAccept()方法会接收异步任务的计算结果作为参数,并进行处理,因此我们可以在回调函数中对计算结果进行任何想要的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值