CompletableFuture 异步编排
CompletableFuture简介
CompletableFuture执行
- CompletableFuture 提供了四个静态方法来创建一个异步操作。runAsync()方法不支持返回值,使用supplyAsync()方法可以获取到返回值,
- 通过指定Executor 来指定线程池来执行异步代码,所有没有显式Executor参数的异步方法都使用ForkJoinPool.commonPool() (除非它不支持至少两个并行级别,在这种情况下,会创建一个新线程来运行每个任务)。
runAsync不支持返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
supplyAsync支持返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
【注意】:默认的commonPool的这些线程都是守护线程。我们在编程的时候需要谨慎使用守护线程,如果将我们普通的用户线程设置成守护线程,当我们的程序主线程结束,JVM中不存在其余用户线程,那么CompletableFuture的守护线程会直接退出,造成任务无法完成的问题!!
代码示例:
private static void syncExecute() throws ExecutionException, InterruptedException{
CompletableFuture<String> t1Future = CompletableFuture.supplyAsync( () -> {
System.out.println( "t1Future 执行中。。。。" );
return "t1Future 执行了";
} );
String t1 = t1Future.get();
System.out.println(t1);
}
CompletableFuture任务执行过程中,出现异常会导致任务中断,因此要对异常进行捕获。
CompletableFuture执行结果
1. get()和join()
作用: 都是用来获取CompletableFuture异步执行结果。
区别:
- join()方法抛出的是uncheck异常(即RuntimeException),不会强制开发者抛出,
- get()方法抛出的是经过检查的异常,ExecutionException, InterruptedException 需要用户手动处理(抛出或者 try catch)
2. whenComplete & whenCompleteAsync
- 将CompletableFuture任务的执行结果及异常信息,作为参数传递到whenComplete函数中。
- CompletableFuture任务执行完成时,执行给定的操作,不论任务是否出现异常,都会调用whenComplete函数。
- whenComplete函数执行完成后,会返回任务执行结果。如果whenComplete出现异常,任务执行将会中断,因此,要对异常进行捕获,并抛出。
//当前线程继续执行
public CompletionStage<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
//提交线程池执行(默认线程池)
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action);
//指定线程池(指定的Executor)
public CompletionStage<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor);
区别:
- whenComplete:是执行当前任务的线程继续执行whenComplete任务
- whenCompleteAsync:是把whenCompleteAsync这个任务提交给线程池来执行
3.exceptionally
- 返回一个新的CompletableFuture,当前面的CompletableFuture完成时,它也完成,当它异常完成时,给定函数的异常触发这个CompletableFuture的完成。
- 任务出现异常时,会优先执行该方法。
代码示例:
private static void exceptionallyTest() throws ExecutionException, InterruptedException{
CompletableFuture<String> t1Future = CompletableFuture.supplyAsync( () -> {
try{
Thread.sleep( 50 );
}
catch( InterruptedException e ){
e.printStackTrace();
}
System.out.println( "t1Future 执行中。。。。" );
int a = 10 / 0;
return "t1Future 执行了";
} );
t1Future.whenComplete( new BiConsumer<String, Throwable>(){
@Override
public void accept( String s, Throwable throwable ){
System.out.println( "t1Future执行完成 值:" + s + ",whenComplete执行中。。" );
}
} );
t1Future.exceptionally( new Function<Throwable, String>(){
@Override
public String apply( Throwable throwable ){
System.out.println( "t1Future执行异常,exceptionally执行中。。" );
return "exceptionally";
}
} );
t1Future.get();
}
执行结果:
t1Future 执行中。。。。
t1Future执行异常,exceptionally执行中。。
t1Future执行完成 值:null,whenComplete执行中。。
多任务组合
并行执行
- allOf (与)当所有给定的 CompletableFuture 完成时,返回一个新的 CompletableFuture。
- anyOf (或)当任何一个给定的CompletablFuture完成时,返回一个新的CompletableFuture。
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
1. allOf
等待所有给定任务执行完成后,才会继续执行。
private static void multiTask() throws ExecutionException, InterruptedException{
CompletableFuture<String> t1Future = CompletableFuture.supplyAsync( () -> {
System.out.println( "t1Future 执行中。。。。" );
return "t1Future 执行了";
} );
CompletableFuture<String> t2Future = CompletableFuture.supplyAsync( () -> {
System.out.println( "t2Future 执行中。。。。" );
return "t2Future 执行了";
} );
CompletableFuture<String> t3Future = CompletableFuture.supplyAsync( () -> {
System.out.println( "t3Future 执行中。。。。" );
return "t3Future 执行了";
} );
CompletableFuture[] completableFutures = new CompletableFuture[]{ t1Future, t2Future, t3Future };
//所有任务执行完成后
CompletableFuture.allOf( completableFutures ).whenComplete( ( v, t ) -> {
for( CompletableFuture completableFuture : completableFutures ){
try{
System.out.println( completableFuture.get());
}
catch( Exception e ){
e.printStackTrace();
}
}
} ).get();
System.out.println( "所有任务全部执行完成。。。。" );
}
2.anyOf
只要给定的任务中,有一个执行完成就会继续执行,用于多条件只要满足一个就行继续的场景
CompletableFuture[] completableFutures = new CompletableFuture[]{ t1Future, t2Future, t3Future };
CompletableFuture.anyOf( completableFutures ).whenComplete( ( v, t ) -> {
System.out.println("whenComplete 执行中。。。。 ");
} ).get();
System.out.println( "所有任务全部执行完成。。。。" );
执行结果
t1Future 执行中。。。。
whenComplete 执行中。。。。
所有任务全部执行完成。。。。
串行执行
- thenApply():把前面任务的执行结果,交给后面的Function
- thenCompose():用来连接两个有依赖关系的任务,结果由第二个任务返回
thenApply 和 thenCompose的区别:
- thenApply转换的是泛型中的类型,返回的是同一个CompletableFuture;
- thenCompose将内部的CompletableFuture调用展开来并使用上一个CompletableFutre调用的结果在下一步的CompletableFuture调用中进行运算,是生成一个新的CompletableFuture。
3.thenApply()
public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn);
public <U> CompletionStage<U> thenApplyAsync(Function<? super T,? extends U> fn,Executor executor);
代码示例
CompletableFuture<Integer> t1Future = CompletableFuture.supplyAsync( () -> {
int result = 10;
System.out.println( "t1Future 执行中。。。。" );
return result;
} ).thenApply( new Function<Integer, Integer>(){
@Override
public Integer apply( Integer s ){
return s * 2;
}
} );
//简写
CompletableFuture<Integer> t2Future = CompletableFuture.supplyAsync( () -> {
int result = 10;
System.out.println( "t1Future 执行中。。。。" );
return result;
} ).thenApply( item -> {
return item * 3;
} );
System.out.println( t1Future.get() );
System.out.println( t2Future.get() );
and集合关系
- thenCombine():合并任务,有返回值
- thenAccepetBoth():两个任务执行完成后,将结果交给thenAccepetBoth处理,无返回值
- runAfterBoth():两个任务都执行完成后,执行下一步操作(Runnable类型任务)
4.thenCombine()
合并任务,并将任务结果作为所提供函数的参数,返回一个新的CompletionStage
public <U,V> CompletionStage<V> thenCombine (CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
//使用默认线程池,异步执行
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn);
//指定线程池,异步执行
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor);
代码示例
private static void test2() throws ExecutionException, InterruptedException{
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync( () -> {
int result = 10;
return result;
} );
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync( () -> {
int result = 20;
return result;
} );
CompletableFuture<Integer> resultFuture = future1.thenCombine( future2, new BiFunction<Integer, Integer, Integer>(){
@Override
public Integer apply( Integer integer, Integer integer2 ){
Integer result = integer + integer2;
return result;
}
} );
System.out.println( "resultFuture=" + resultFuture.get() );
}
4.thenAccepetBoth()
当此阶段和另一个给定阶段都正常完成时,将使用两个结果作为所提供操作的参数来执行该阶段,无返回值。
public <U> CompletionStage<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync (CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action);
public <U> CompletionStage<Void> thenAcceptBothAsync (CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action,Executor executor);
代码示例
CompletableFuture<Void> resultFuture = future1.thenAcceptBoth( future2, new BiConsumer<Integer, Integer>(){
@Override
public void accept( Integer integer, Integer integer2 ){
int result = integer + integer2;
System.out.println( "执行结果:" + result );
}
} );
or聚合关系
- applyToEither():两个任务哪个执行的快,就使用哪一个结果,有返回值
- acceptEither():两个任务哪个执行的快,就消费哪一个结果,无返回值
- runAfterEither():任意一个任务执行完成,进行下一步操作(Runnable类型任务)
5.applyToEither()
当此阶段或其他给定阶段正常完成时,该阶段将以相应的结果作为所提供函数的参数执行。有返回值。哪个执行的快,就使用哪一个结果,有返回值。
public <U> CompletionStage<U> applyToEither (CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn);
public <U> CompletionStage<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn, Executor executor);
代码示例
CompletableFuture<Integer> resultFuture = future1.applyToEither( future2, new Function<Integer, Integer>(){
@Override
public Integer apply( Integer integer ){
System.out.println("执行结果:"+integer);
return integer;
}
} );
6.acceptEither()
两个任务哪个执行的快,就消费哪一个结果,无返回值
当此阶段或其他给定阶段正常完成时,该阶段将以相应的结果作为所提供操作的参数执行。
public CompletionStage<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletionStage<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action, Executor executor);
代码示例
CompletableFuture resultFuture = future1.acceptEither( future2, new Consumer<Integer>(){
@Override
public void accept( Integer integer ){
System.out.println( "执行结果:" + integer );
}
} );
resultFuture.get();
7.runAfterEither()
任意一个任务执行完成,进行下一步操作(Runnable类型任务)
public CompletionStage<Void> runAfterEither(CompletionStage<?> other, Runnable action);
public CompletionStage<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action);
public CompletionStage<Void> runAfterEitherAsync (CompletionStage<?> other, Runnable action, Executor executor);
代码示例
CompletableFuture resultFuture = future1.runAfterEither( future2, new Runnable(){
@Override
public void run(){
System.out.println("执行runnable......");
}
} );
resultFuture.get();