异步编程CompletableFuture

一:创建对象

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)

说明:没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。

  • runAsync方法不支持返回值。
  • supplyAsync 支持返回值。

示例:

/**
 * CompletableFuture 提供了四个静态方法来创建一个异步操作。
 *
 */
public class CompletableFutureDemo1 {
    public static void main(String[] args) {

        /** 第一种 runAsync 不支持返回值的 */
        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
            System.out.println("runAsync 不支持返回值");
        }).whenComplete((t,u)->{
            System.out.println("runAsync 完成");
        });


        /** 第二种 supplyAsync 支持返回值 */
        CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
            int i = 10;
            return i;
        }).whenComplete((t, u) -> {
            System.out.println("supplyAsync 完成,返回值是" + t);
        });

    }
}

运行结果:
runAsync 不支持返回值
runAsync 完成
supplyAsync 完成,返回值是10

二:计算完成时回调方法

当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:

public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action);
返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行特定动作的结果(或 null如果没有)和异常(或 null如果没有)这个阶段。 

public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action);
返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行特定动作执行给定的操作这一阶段的默认的异步执行设施,其结果(或 null如果没有)和异常(或 null如果没有)这个阶段作为参数。

public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor);
返回相同的结果或例外,这一阶段的新completionstage,这个阶段完成时,执行使用所提供的遗嘱执行人,给出的行动与结果(或 null如果没有)和异常(或 null如果没有)这个阶段作为参数。 

public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn);
返回一个新的completablefuture已经完成与给定值。 

示例:

 /**
         * whenCompleteAsync 依赖于上一层的CompletableFuture 的返回值作为这个阶段的参数进行某些操作,返回的仍然是上一层的CompletableFuture
         * whenCompleteAsync和whenComplete的区别:
         *    whenCompleteAsync为异步,可能并不是执行上一层代码的线程
         *    whenComplete为执行上一层代码的线程执行这个阶段的逻辑
         *
         */
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }).whenCompleteAsync((t, u) -> {
            int m = t*2;  //可以利用回调值做一些操作计算
            System.out.println("上一层依赖的CompletableFuture返回的结果是:" + t);
            System.out.println("上一层依赖的CompletableFuture返回的结果是:" + u);
        });
        Integer result = future.get();
        System.out.println("CompletableFuture.whenCompleteAsync运行后结果是:"+result);

运行结果:
上一层依赖的CompletableFuture返回的结果是:5
上一层依赖的CompletableFuture返回的结果是:null
CompletableFuture.whenCompleteAsync运行后结果是:5

运行后可以发现whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)中的第一个参数即是上一层回调的返回值,那第二个参数是什么呢?看下面这个示例

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }).whenCompleteAsync((t, u) -> {
            System.out.println("上一层依赖的CompletableFuture返回的结果t是:" + t);
            System.out.println("上一层依赖的CompletableFuture返回的结果u是:" + u);
        });

运行结果:

上一层依赖的CompletableFuture返回的结果t是:null
上一层依赖的CompletableFuture返回的结果u是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero

所以第二个参数就是上一层回调出现的异常信息。OK
那么exceptionally这个方法则是在回调时遇到异常后可以进行的某些操作,看一个示例:

CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }).exceptionally(t -> {
            System.out.println("返回结果t:" + t);
            return 100;
        });
        System.out.println("CompletableFuture.exceptionally运行结果:"+future1.get());

运行结果:

返回结果t:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
CompletableFuture.exceptionally运行结果:100

所以在exceptionally方法中可以在接收到回调方法异常时可以做一些操作。

三:线程串行化方法

thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值

thenAccept方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。

thenRun方法:只要上面的任务执行完成,就开始执行thenRun,只是处理完任务后,执行 thenRun的后续操作

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
当一个线程依赖另一个线程时,获取上一个任务返回的结果,**并返回当前任务的返回值**。(有返回值)

public CompletionStage<Void> thenAccept(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
消费处理结果。接收任务的处理结果,并消费处理,**无返回结果。

public CompletionStage<Void> thenRun(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action);
public CompletionStage<Void> thenRunAsync(Runnable action,Executor executor);
只要上面的任务执行完成,就开始执行thenRun,**只是处理完任务后,执行 thenRun的后续操作

每一个方法都对应了三种操作。带有Async默认是异步执行的。这里所谓的异步指的是不在当前线程内执行。带有参数Executor executor的则用指定的线程池方案,不指定的话则用默认的ForkJoinPool.commonPool()。

说明:(Function<? super T,? extends U> fn)
​ T : 上一个任务返回结果的类型
​ U:当前任务的返回值的类型

示例thenApplyAsync:

 @Test
    public void testThenApply() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> thenApply = CompletableFuture.supplyAsync(() -> {
            return 100;
        }).thenApplyAsync(t -> {
            return t * 2;
        });
        Integer result = thenApply.get();
        System.out.println(result);
    }
运行结果:200

示例

 @Test
    public void testThenAcceptAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        }).thenAcceptAsync(t -> {
            t = t*2;
            System.out.println("t========>"+t);
        });
        System.out.println(future.get());
    }
    
    运行结果:t========>200
			null

四:两任务组合 - 都要完成

两个任务必须都完成,触发该任务。

thenCombine:组合两个future,获取两个future任务的返回结果,并返回当前任务的返回值

thenAcceptBoth:组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值。

runAfterBoth:组合两个future,不需要获取future的结果,只需两个future处理完任务后,处理该任务

public <U,V> CompletableFuture<V> thenCombine(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn);

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn);

public <U,V> CompletableFuture<V> thenCombineAsync(
    CompletionStage<? extends U> other,
    BiFunction<? super T,? super U,? extends V> fn, Executor executor);
 组合两个future,获取两个future任务的返回结果,并返回当前任务的返回值   

public <U> CompletableFuture<Void> thenAcceptBoth(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action);

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action);

public <U> CompletableFuture<Void> thenAcceptBothAsync(
    CompletionStage<? extends U> other,
    BiConsumer<? super T, ? super U> action, Executor executor);
组合两个future,获取两个future任务的返回结果,然后处理任务,没有返回值。

public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
                                            Runnable action);

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action);

public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
                                                 Runnable action,
                                                 Executor executor);
组合两个future,不需要获取future的结果,只需两个future处理完任务后,处理该任务

五:多任务组合

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);

public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);

说明:
allOf:等待所有任务完成
anyOf:只要有一个任务完成

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值