【Java】多线程JUC中的CompletedFuture教程详解-增强Future以及CompetionStage概念引入的理解学习、开发使用、任务编排等,看此一篇就够

CompletedFuture 实现方式简单理解

CompletedStage接口代表异步计算过程中的某一个阶段;一个阶段完成后可能触发其他阶段(一个阶段的执行可能是由某个阶段的完成触发,也可能是由多个阶段一起完成触发);CompletedStage接口提供Function、Consumer或者Runnable类型的入参并再转换为CompletedStage类型,赋予了函数式编程链式调用的能力;

CompletableFuture<T>
«Interface»
CompletionStage<T>
«Interface»
Future<V>

CompletedFuture实现并增强Future和CompletedStage接口,Future代表着异步任务结果相关对象,CompletedStage代表任务执行过程的某一阶段能有转化为下一阶段的能力,意味着CompletedFuture即可以看作执行过程中的某一个阶段能转换为下一个阶段,又可以看作最终结果调用get、join等方法得到异步计算结果;

这种设计很巧妙的运用了多态特性,CompletableFuture按照场景即可以被认定为CompletionStage类型也可以认定为Future;例如CompletionStage a = new CompletableFuture()时表示了通过a只能调用到CompletionStage 定义的方法,而Future中赋予的职能可以被屏蔽,这是个很好的设计方式;

CompletaleFuture工具类使用详解

使用方法如下,先使用CompletedFuture提供的静态方法执行第一个阶段,往后阶段使用上一阶段返回的CompletedFuture实例调用其实例方法即可:

  1. CompletedFuture中的静态方法runSync、supplyAsync分别能传入Runnable和Suppier参数代码片段,代表无返回结果和有返回结果的异步任务执行;执行时可传入自定义线程池,若未传入则使用默认的ForkJoinPool.commonPool线程池(该线程池仅适合执行CPU密集型任务,并且核心线程数仅为1);该方法返回CompletableFuture可获取结果或调用其实例方法执行异常处理或下一阶段的计算;

    public static CompletableFuture<Void> runAsync(Runnable runnable)
    public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
    
  2. 下一阶段的计算:通过静态方法调用第一阶段执行后得到的CompletedFuture实例,调用其thenRun、thenApply方法(分别代表无返回值任务和有返回值任务)可以带入上一阶段结果并进入下一阶段计算;上一阶段发生异常未处理后thenAccept、thenRun、thenApply均不会被调用;

    public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn);
    public CompletionStage<Void> thenRun(Runnable action);
    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
    
  3. 异常处理:whenComplete、handle方法会把上一阶段执行结果或异常信息带入;无论上一阶段执行成功还是出现异常均会调用,出现异常时执行结果为null,无异常时异常入参为null;区别在于handle入参为BiFunction可改变CompletedFuture的结果(或类型),而whenComplete入参为BiConsumer不支持返回新值,适用于记录日志等副操作场景;exceptionally方法仅仅会在上一阶段发生异常时调用,可以修改返回值(区别于handle但不能修改类型);

    public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
    public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
    public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
    

    handle示例:

    public static void handle() throws Exception{
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(new Supplier<Integer>() {
            @Override
            public Integer get() {
                int i= 10/0;
                return new Random().nextInt(10);
            }
        }).handle(new BiFunction<Integer, Throwable, Integer>() {
            @Override
            public Integer apply(Integer param, Throwable throwable) {
                int result = -1;
                if(throwable==null){
                    result = param * 2;
                }else{
                    System.out.println(throwable.getMessage());
                }
                return result;
            }
         });
        System.out.println(future.get());
    }
    
  4. 实例方法如whenComplete、handle等等(几乎所有的实例方法都有对应的Async方法)均有对应的whenCompleteAsync、handleAsync方法;前者代表使用执行上一阶段的线程执行本阶段,后者代表将本阶段提交给线程池执行,后者也可以传入新的线程池执行;

    public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
    public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
    public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
    //等等
    

任务组合编排方法

  1. 合并任务:thenCombine实例方法支持传入另一个CompletionStage和BiFunction代码片段,当两个CompletionStage计算完成时将计算结果传入BiFunction进行下一步转换,支持返回新的计算结果以及类型;thenAcceptBoth区别于thenCombine,两个阶段执行完成后将计算结果传入BiConsumer代码片段进行消耗,意味着不能返回新的计算结果,适用于记录日志等副操作场景;runAfterBoth区别于上两种,可传入Runnable代码片刻执行无需上阶段结算结果的任务;

    public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
    public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
    
  2. Either转换:区别于任务合并,只要任何一阶段先执行完毕时就取消并列的另一阶段,并用先完成阶段的结果进行下一阶段转换;applyToEither实例方法可传入Function代码片段返回新结果或类型;acceptEither实例方法可传入Consumer代码片段对上一阶段执行结果进行消耗;runAfterEither可传入Runnable参数适用于副操作等场景;

    public <U> CompletionStage<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
    public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,Runnable action);
    
  3. 流水线:thenCompose实例方法允许对两个CompletionStage进行流水线操作;效果和thenApply一样,但区别于apply返回CompletableFuture<CompletableFuture<U>>,这里返回的是CompletableFuture<U>,代表第一阶段已经计算出结果才调用的第二阶段;

    public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
    

    thenApply内部实际上创建了一个嵌套的 CompletableFuture<CompletableFuture<U>>,然后将其扁平化为 CompletableFuture<U>;thenCompose 直接返回 CompletableFuture<U>,并且在内部处理了嵌套的 CompletableFuture,避免了多层嵌套;thenCompose 适用于当你希望将两个异步操作串联起来,并且第二个操作依赖于第一个操作的结果;thenApply 适用于当你希望对第一个操作的结果进行转换,但不涉及进一步的异步操作时;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值