【多线程】CompletableFuture基础解析

【前言】         

         之前一篇博客---《采用Callable接口创建线程》介绍了,Callable接口,它优化了Runable接口,而其中Future接口又代表了Callable接口中的call()方法的返回值。

         Future是一种多线程设计模式,可以让用户把要执行的方法交给它,同时可以处理其他的业务逻辑,过段时间可从Future那里取出结果,一般和Callable结合(可使用ExecutorService的submit执行Callable,返回Future)使用。     

         

        Future模式的虽然可以实现异步执行结果,但

       ①只能通过轮询IsDone确认完成之后,使用阻塞的get()方法来获取值。(或者调用get(long timeout, TimeUnit unit)防止程序无限制等待结果)

      ②没有通知机制,无法得知何时结束,而且isDone会耗费CPU资源

      ③异步返回的结果与结果之间,无法建立结果之间的联系。(比如:将两个异步结果合并,or只等待最快的任务,or等待所有任务都结束)

       故引出我们今天的主题-CompletableFuture类。(推荐阅读第一条链接)

 

【介绍】

       ①位于java.util.concurrent包下。

       ②CompletableFuture类提供了强大的Future的扩展功能,简化异步编程的复杂度,提供了函数式编程的能力,可通过回调的方式处理计算结果。

       ③ CompletableFuture类实现了CompletionStage和Future接口。     

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> 

        ④在没有指定Executor的情况下,异步执行通过ForkJoinPool来实现,使用守护线程去执行任务。

 

     特点:

       ① 非阻塞;

       ②可将异步结果交给另一个异步事件处理线程(不着急要结果,先返回一个结果,后台继续执行那些需要长时间执行的方法,真正需要的时候,再去get真正的结果)。(推荐阅读第二条链接)

      ③对比联系ForkJoin框架,它是将任务分解为独立的子任务,适用于(处理元素独立,数据集要大,每个任务的处理成本要高,才能弥补框架本身消耗的成本),而CompletableFuture类在ForkJoin的基础上做了创新。

       

【方法】

    1、静态工厂方法

          runAsync(Runnable runnable):使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。

          runAsync(Runnable runnable, Executor executor)使用指定的thread pool执行异步代码。

          supplyAsync(Supplier<U> supplier)使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值 

          supplyAsync(Supplier<U> supplier, Executor executor)使用指定的thread pool执行异步代码,异步操作有返回值

      2、其他方法

            参考:推荐阅读第三条链接

 

【一个简单的事例】

    异步查询多个班级的学生人数

   

/**
     * 传入classId列表,异步查询每个班的招生人数
     *
     * @param classIds 传入classId列表
     * @return 每个班的招生人数
     */
    @Override
    public CompletableFuture<List<Map<Long, Integer>>> getStudentCountByClassIds(List<Long> classIds) {

         final List<CompletableFuture<Map<Long, Integer>>> collect = classIds.parallelStream().map(s -> CompletableFuture.supplyAsync(() -> {
            Map<Long, Integer> map = new HashMap<>();
            final int count = progressService.queryClassStudentNumByClassId(s);
            map.put(s, count);
            return map;
        })).collect(Collectors.toList());
        
        CompletableFuture<List<Map<Long, Integer>>> sequence = sequence(collect);
        log.info("sequence方法 costTime:{}" ,System.currentTimeMillis()-time);
//        CompletableFuture<Integer> totalCount = sequence.thenApply(m -> m.stream().map(s -> s.values().stream().findAny().get()).reduce((a, b) -> a + b).get());
        return sequence;
    }
    //endregion

    private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures){
        CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));

        return completableFuture.thenApply(v->
                futures.stream()
                        .map(future-> future.join())
                        .collect(Collectors.toList())
                );
    }

 

【推荐阅读】

  Java8新的异步编程方式 CompletableFuture(一)

  Java并发编程系列一:Future和CompletableFuture解析与使用

  20 个使用 Java CompletableFuture的例子

  

推荐一个公众号,免费领架构师学习资料,每周更新优质文章,能学到很多。

                  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值