Java 8 中的 CompletableFuture使用

228 阅读6分钟

CompletableFuture的常见规则:

  1. 函数的执行方式一般有同步和异步两种,异步方式以Async结尾、默认使用ForkJoinPool执行,也可以使用指定的executor。如:CompletableFuture.complete和CompletableFuture.completeAsyn
  2. 被执行的函数一般有三种:应用函数applyXXX、消费函数acceptXXX、可执行函数runXXX。如:thenApply、thenAccept、thenRun,主要区别为是否接收参数及有无返回结果。
Function<? super T, U> fn:应用函数,接收前一阶段返回结果作为入参,有返回值
Consumer<? super T> action:消费函数:接收前一阶段返回结果作为入参,无返回值
Runnable action:执行函数:无入参,无返回值
  • 静态方法创建CompletableFuture对象:
completedFuture:创建一个已经完成的 CompletableFuture 对象,其结果值为指定的值 value。
supplyAsync:创建一个异步执行的 CompletableFuture 对象,异步执行给定的供应者函数,返回计算结果。
runAsync:创建一个异步执行的 CompletableFuture 对象,异步执行给定的可运行任务,不返回结果。
completedStage:创建一个已经完成的阶段(stage) CompletableFuture 对象,其结果值为指定的值 value。
failedFuture:创建一个已经完成且异常的 CompletableFuture 对象,其结果为给定的异常 ex。
  • 链式执行:

阻塞执行完前一个方法后才会执行后一个方法,如:

//执行顺序是f1->f2->f3,不论是异步执行还是同步执行的,都是将前一阶段的结果作为入参传入到下一个方法
CompletableFuture.completedFuture("message").thenApplyAsync(f1).thenApplyAsync(f2).thenApplyAsync(f3)

下列方法中,除了exceptionally外,都有对应的Asyn函数异步执行方法,exceptionally对应的异步异常处理可以用handleAsyn

thenApply:当异步操作执行成功时,用前一阶段的结果作为参数,接收一个处理函数,有返回结果
thenCompose:与thenApply类似,区别为thenApply的fn是对前一步的返回值进行处理,thenCompose的fn是对另一个CompletableFuture进行处理
thenAccept:当异步操作执行成功时,用前一阶段的结果作为参数,接收一个处理函数,不返回结果。
thenRun:当异步操作执行成功时,不接收参数,接收一个Runnable函数,不返回结果。
handle:无论操作是成功还是失败,用前一阶段的结果作为参数,接收一个处理函数,有返回结果。
whenComplete:无论操作是成功还是失败,用前一阶段的结果作为参数,接收一个处理函数,不返回结果。
exceptionally:当异步操作发生异常时,接收异常,接收一个处理函数,有返回结果。
  • 手动完成CompletableFuture对象:
complete:手动将'未完成'CompletableFuture对象变为完成状态,并设置它的结果值,返回手动执行的结果,它的依赖关系和后续操作仍然会按照正常的异步操作流程进行。
completeAsync:与 complete不同的是,completeAsync以异步的方式执行。
obtrudeValue:'强制'完成 CompletableFuture 对象,并设置一个成功的结果值。与 complete方法不同的是,obtrudeValue方法会立即完成 CompletableFuture 对象,而不考虑对象的状态。如果 CompletableFuture 对象已经完成或已经异常完成,obtrudeValue方法将强制替换结果值。该方法不会触发后续的回调函数或链式操作。
completeExceptionally:将异步操作标记为异常完成,并将指定的异常传递给后续的异常处理函数或链式操作
obtrudeException:强制完成 CompletableFuture 对象,并设置一个异常作为结果。与 completeExceptionally方法不同的是,obtrudeException方法会立即完成 CompletableFuture 对象,而不考虑对象的状态。如果 CompletableFuture 对象已经完成或已经异常完成,obtrudeException方法将强制替换异常结果。该方法不会触发后续的异常处理函数或链式操作。
cancel:尝试取消 CompletableFuture 对象的执行。如果取消成功,CompletableFuture 对象的状态将被标记为已取消,并且任何等待该对象完成的线程将接收到 CancellationException 异常
  • 判断执行结果状态:
isCompletedNormally:用于检查 CompletableFuture 对象是否已经正常完成,即没有抛出异常
isDone:无论CompletableFuture 是正常完成、异常完成、还是被取消,只要任务结束了都返回true否则返回false
isCancelled:CompletableFuture是否被取消
isCompletedExceptionally:CompletableFuture是否异常完成
  • 获取执行结果
join:阻塞当前线程获取返回结果值,如果任务执行异常时join方法会抛出异常,(用handle方法替换join方法使用)
get:阻塞当前线程获取返回结果值,可以设置等待时间
getNow:不阻塞立即获取结果值,如果有值了则返回,否则返回getNow传入的默认值
  • 两个任务组合
applyToEither:两个CompletableFuture 中任意一个完成时,接收参数执行应用函数,有返回结果
acceptEither:两个CompletableFuture 中任意一个完成时,接收参数执行消费函数,无返回结果
thenCombine:两个CompletableFuture 都完成时,运行给定的方法,接收两个任务的结果作为入参,有返回结果
thenAcceptBoth:两个CompletableFuture 都完成时,运行给定的方法,接收两个任务的结果作为入参,无返回结果
runAfterBoth:两个CompletableFuture 都完成时,运行给定的方法,不接收参数,无返回结果

例子:
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
	//doSomething
	return "1";
});
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
	//doSomething
	return "2";
});
CompletableFuture<String> cf3 = cf1.applyToEither(cf2, Function.identity());
System.out.println(cf3.join());
说明:
Function.identity() 表示一个恒等函数,它接受一个参数并将其作为返回结果,cf1与cf2哪个先执行完则输出哪个任务的结果,在真实的场景中可以将Function.identity()改为自己的执行函数。

  • 多个任务组合
allOf:用于条件与的汇总场景,生成新的CompletableFuture ,当所有任务都正常完成(无异常)时才算完成,没有返回结果,当任务集合中的某个任务异常时,其他的任务也会执行
anyOf:用于条件或场景,生成新的CompletableFuture ,只要有一个正常完成(无异常)就算完成,返回第一个完成的CompletableFuture结果值

例子:
public void testAllof(){
    CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
        timeCost(2000);
        return "1";
    });
    CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
        timeCost(1000);
        throw new RuntimeException("");
    });
    CompletableFuture<String> cf3 = CompletableFuture.supplyAsync(() -> {
        timeCost(3000);
        return "3";
    });

    List<CompletableFuture<String>> cfList = Arrays.asList(cf1, cf2, cf3);
    CompletableFuture[] arrs = cfList.toArray(CompletableFuture[]::new);
    //需要用handle处理转换,防止cfList某个任务执行异常,不然使用join方法时会报错
    CompletableFuture<String> allFuture = CompletableFuture.allOf(arrs).handle((v,ex)->{
        if (ex != null) {
            return "someone error";
        }else{
            return "all success";
        }
    });
    //当cfList某个任务异常时,用join方法等待allOf生成的CompletableFuture会抛异常,所以用handle处理allOf生成新的CompletableFuture,同时任务集合的执行结果
    CompletableFuture<List<String>> allOf = CompletableFuture.allOf(arrs).handle((v, th) -> {
            //收集cfList结果
            List<String> list = cfList.stream().map(i -> {
                    String tmp = i.handle((val, ex) -> {
                            return val;
                    }).join();
                    return tmp;
            }).collect(Collectors.toList());
            return list;
    });
    List<String> res = allOf.join();
    System.out.println(res);

参考:mp.weixin.qq.com/s/9fq9TQC-o…