CompletableFuture是什么
- CompletableFuture是Java8中提供的Future的扩展功能,简化异步编程的复杂性;
- 引入函数式编程,通过回调的方式处理计算结果,也提供了转换和组合的方法;
- 它实现了Future和CompletionStage接口;
- 借助CompletionStage的方法可以实现链式调用;
- 一个CompletetableFuture就代表了一个任务,可以用then,when等操作来防止阻塞和轮询isDone的现象出现;
- 它可能代表一个明确完成的Future,也有可能代表一个完成阶段( CompletionStage ),它支持在计算完成以后触发一些函数或执行某些动作;
创建方式
1、创建一个具有默认结果的 CompletableFuture,不经常使用;
2、supplyAsync表示创建带返回值的异步任务,相当于ExecutorService submit(Callable<T> task),这两方法的效果跟submit是一样的。
3、runAsync表示创建无返回值的异步任务,相当于ExecutorService submit(Runnable task);
样例:
public static void main(String[] args) {
// runAsync的使用
CompletableFuture<Void> runFuture = CompletableFuture.runAsync(() -> System.out.println("Hello runAsync!"));
// supplyAsync的使用
CompletableFuture<String> supplyFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("Hello supplyAsync!");
return "Hello World";
});
// runAsync的future没有返回值,输出null
System.out.println("runAsync结果:" + runFuture.join());
// supplyAsync的future,有返回值
System.out.println("supplyAsync结果:" + supplyFuture.join());
}
结果:
创建形式:
1、默认的使用公共的 ForkJoinPool 线程池执行(默认线程数是 CPU 的核数);如果机器是单核的,则默认使用ThreadPerTaskExecutor,该类是一个内部类,每次执行execute都会创建一个新线程
2、提供一个主动创建线程池,相比于ForkJoinPool的好处是,可以通过自定义不同场景的线程池,来进行业务划分方便发现问题,还有一个好处就是ForkJoinPool是一种共享线程,发生阻塞会造成其他线程无法获取执行机会。
注:自定义线程池有个队列满了的拒绝策略,如果采用丢弃策略的拒绝策略,并且allOf方法和get方法如果没有设置超时则会无限期的等待下去
样例:
public static void main(String[] args) {
CompletableFuture.runAsync(() -> System.out.println("默认线程池执行--" + Thread.currentThread().getName()));
// 可以自定义线程池
ExecutorService executor = Executors.newCachedThreadPool();
CompletableFuture.runAsync(() -> System.out.println("自定义线程池执行--" + Thread.currentThread().getName()), executor);
}
结果:
CompletionStage是什么
Java8新增得一个接口,代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段。目前只有CompletableFuture一个实现类
-
一个阶段的计算执行可以是一个Function,Consumer或者Runnable。比如:stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())
-
一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发
异步回调
then前缀:
某个任务执行完成后执行的动作(即回调方法)可以理解为串行化一个任务接着一个执行
Async后缀的区别:fn是否异步执行
thenApply系列:将上一个任务任务的执行结果,交给后面的Function,返回一个具有处理结果的Future对象
thenAccept系列:将上一个任务任务的执行结果(即方法返回值)作为入参传递到回调方法中,无返回值
thenRun系列:无入参无返回值。不关心结果,只对结果执行Action
thenCompose:用来连接两个有依赖关系的任务
thenApply和thenCompose的区别
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
Function<? super T,? extends U> T:上一个任务返回结果的类型 U:当前任务的返回值类型
两个方法的返回值都是CompletionStage<U>
,不同之处在于它们的传入参数fn
.
- 对于
thenApply
,fn
函数是一个对一个已完成的stage或者说CompletableFuture的的返回值进行计算、操作; - 对于
thenCompose
,fn
函数是对另一个CompletableFuture进行计算、操作。
样例:
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> 123).thenApply(num -> "thenApply任务:" + num);
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> 456).thenCompose(num -> CompletableFuture.supplyAsync(() -> "thenCompose任务:" + num));
System.out.println(f1.join());
System.out.println(f2.join());
聚合
1、将多个CompletableFuture都执行完成以后,才会执行后操作。
2、多个CompletableFuture并行执行,相互之间并没有先后依赖顺序。
3、多个任务中只要有一个执行异常,则将该异常信息作为指定任务的执行结果,返回的CompletableFuture执行get方法时会抛出异常,如果都是正常执行,则get返回null。
and
thenCombine系列:两个任务执行完成后,执行下一步操作Function,有入参有返回值;
thenAcceptBoth系列:两个任务执行完成后,执行下一步操作Consumer,有入参无返回值;
runAfterBoth系列:两个任务都执行完成后,执行下一步操作Runnable,无入参无返回值
allOf:多个CompletableFuture任务,当所有任务完成时,方法返回CompletableFuture<Void>;
or
applyToEither系列:两个任务任意一个完成,执行下一步操作Function,有入参有返回值CompletableFuture<U>(谁执行的快,就使用那一个结果作为后续任务入参);
acceptEither系列:两个任务任意一个完成,执行下一步操作Function,有入参无返回值CompletableFuture<Void>(谁执行的快,就使用那一个结果作为后续任务入参);
runAfterEither系列:两个任务任意一个完成,执行下一步操作Runnable,无入参无返回值CompletableFuture<Void>
anyOf:多个CompletableFuture任务,只要有一个任务执行完成,方法返回CompletableFuture<Object>;
结果或异常处理
whenComplete
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
whenComplete系列:不论上一个阶段是正常/异常完成(即不会对阶段的原来结果产生影响);类似于 try..catch..finanlly 中 finally 代码块,无论是否发生异常都将会执行的。
当某个任务执行完成后,会将执行结果或者执行期间抛出的异常传递给回调方法:
如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,
如果该任务正常执行,则get方法返回执行结果,如果是执行异常,则get方法抛出异常。
handle
public <U> CompletionStage<U> handle (BiFunction<? super T, Throwable, ? extends U> fn);
handle系列:产出型方法,即可以对正常完成的结果进行转换,也可以对异常完成的进行补偿一个结果,即可以改变阶段的现状。跟whenComplete基本一致,区别在于handle的回调方法有返回值,且handle方法返回的CompletableFuture的result是回调方法的执行结果或者回调方法执行期间抛出的异常,与原始CompletableFuture的result无关。
exceptionally
public CompletionStage<T> exceptionally (Function<Throwable, ? extends T> fn);
异常的结果处理(上一个阶段异常完成才会被执行);
使用方式类似于 try catch中的catch代码块中异常处理;当某个任务执行异常时将抛出的异常作为参数传递到回调方法中,如果该任务正常执行,exceptionally方法返回的CompletionStage的result就是该任务正常执行的结果。
结果获取
CompletableFuture方法执行过程若产生异常,只有get或join方法才能获取到异常
get:获取任务返回值,没有则阻塞直到有返回值返回;抛出经过检查的异常InterruptedException, ExecutionException
getNow:如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值;
join:获取任务返回值,没有则阻塞直到有返回值返回;抛出未经检查的异常,不会强制抛出,会将异常包装成CompletionException/CancellationException异常;