特别说明:JDK1.8+之后引入 CompletableFuture
在一些需求中,我们常常要给前端返回一些复杂的视图数据,数据之间可能有关联,比如查询了A数据之后才可以根据A数据中的一些信息来查询B数据。
再比如 查询A数据与查询B数据一般没有相关性。假设查询A数据需要1秒,查询B数据需要1秒,那么以往的写法中,第一种情况返回给前端的时间总共花费2秒,
第二种情况返回给前端的时间也会是2秒。但这并不是我们愿意看到的,既然A数据跟B数据没有依赖性很强的情况下,应该可以并行查询进行封装,这样返回给前端的时间只需要花费1秒,这样大大增大了吞吐量,所以可以使用异步编排来解决该问题。
提供四个静态方法来创建一个异步操作。
//创建异步
public static CompletableFuture<Void> runAsync(Runnable runnable);
//创建异步,支持传入线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);
//创建异步,并返回执行后的结果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> sup);
//创建异步,支持传入线程池,并返回执行后的结果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> sup, Executor executor)
1.runAsync方法都没有返回结果,supplyAsync方法都是有返回结果.
2.可以支持传入自己的线程池,或不传使用默认。
runAsync示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//第一种方式: runAsync
CompletableFuture.runAsync(() -> {
System.out.println("执行runAsync方法....");
}, executorService);
System.out.println("执行main方法....");
//结果:
//执行main方法....
//执行runAsync方法....
supplyAsync示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//第二种方式:supplyAsync
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("执行supplyAsync方法...");
return "hello,world";
}, executorService);
System.out.println("返回的结果是:"+future.get());
System.out.println("执行main方法....");
/**
结果:
执行supplyAsync方法...
返回的结果是:hello,world
执行main方法....
*/
某个异步任务完成之后执行某个任务
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action);
//成功后回调异步执行,arg1:上次执行的结果,arg2:上次执行的异常
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action);
//成功后回调异步执行,支持传入自己的线程池。arg1:上次执行的结果,arg2:上次执行的异常
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor);
whenComplete与whenCompleteAsync 区别在于 一个是上一个执行完的线程继续执行,一个是交由其他线程来执行。
whenComplete示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//完成回调 成功后执行某个事情
CompletableFuture.supplyAsync(()->{
System.out.println("刷牙....");
return "先刷牙";
},executorService).whenComplete((res,err)->{
System.out.println("洗脸..."+"上一次结果:"+res+"--错误:"+err);
});
System.out.println("执行main方法....");
/*
刷牙....
洗脸...上一次结果:先刷牙--错误:null
执行main方法....
*/
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//完成回调 成功后执行某个事情
CompletableFuture.supplyAsync(()->{
System.out.println("刷牙....");
int i=1/0;
return "先刷牙";
},executorService).whenComplete((res,err)->{
System.out.println("洗脸..."+"上一次结果:"+res+"--错误:"+err);
});
System.out.println("执行main方法....");
/*
执行main方法....
刷牙....
洗脸...上一次结果:null--错误:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
*/
虽然能得到异常信息,但是没办法修改返回数据。使用方法exceptionally可以得到解决。
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//完成回调 成功后执行某个事情
CompletableFuture<String> exceptionally = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙....");
int i = 1 / 0;
return "先刷牙";
}, executorService).whenComplete((res, err) -> {
System.out.println("洗脸..." + "上一次结果:" + res + "--错误:" + err);
}).exceptionally(e->{
return "异常了";
});
System.out.println("执行结果:"+exceptionally.get());
System.out.println("执行main方法....");
/*
刷牙....
洗脸...上一次结果:null--错误:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
执行结果:异常了
执行main方法....
*/
以上的whenComplete 以及exceptionally 都可以用handler代替
//由上一个执行的线程来继续执行 T:上一次执行的结果 U:返回结果
public <U> CompletableFuture<U> handle(
BiFunction<? super T, Throwable, ? extends U> fn);
//由其他线程来执行 T:上一次执行的结果 U:返回结果
public <U> CompletableFuture<U> handleAsync(
BiFunction<? super T, Throwable, ? extends U> fn);
//由其他线程来执行,支持传入线程池。 T:上一次执行的结果 U:返回结果
public <U> CompletableFuture<U> handleAsync(
BiFunction<? super T, Throwable, ? extends U> fn, Executor executor);
handle示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<String> handle = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
int i = 1 / 0;
return "正常刷完牙了";
}).handleAsync((res, err) -> {
if (res != null) {
return res;
}
if (err != null) {
return "刷牙的时候有问题";
}
return "返回值是null,但也没抛异常";
},executorService);
System.out.println("执行结果:"+handle.get());
System.out.println("执行main方法....");
/*
刷牙...
执行结果:刷牙的时候有问题
执行main方法....
*/
//上一个任务执行后,接下来执行的任务 由上一次任务执行后的线程继续执行.
public CompletableFuture<Void> thenRun(Runnable action);
//上一个任务执行后,接下来执行的任务 由不同的线程继续执行.
public CompletableFuture<Void> thenRunAsync(Runnable action);
//上一个任务执行后,接下来执行的任务 由线程池继续执行.
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor);
//上一个任务执行后,接收并接下来执行的任务
public CompletableFuture<Void> thenAccept(Consumer<? super T> action);
//上一个任务执行后,接收并接下来执行的任务
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action);
//上一个任务执行后,接收并接下来执行的任务
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor);
//上一个任务执行后,接收并接下来执行的任务,并返回结果
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);
thenRun都是无返回值的,不需要上一次任务执行的结果。
thenAccept 都是可以接收到上一次任务执行的结果,用于下一次执行使用。
thenApply 接收上一次执行的结果,并有返回值。
thenRun示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return null;
}, executorService).thenRun(() -> {
System.out.println("洗脸");
});
//阻塞等待方法
future.get();
/*
刷牙...
洗脸
*/
thenAccept示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return "我刷完了";
}, executorService).thenAcceptAsync(result -> {
System.out.println("接收结果:"+result);
System.out.println("洗脸");
});
//阻塞等待方法
future.get();
/*
刷牙...
接收结果:我刷完了
洗脸
*/
thenApply示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return "我刷完了";
}, executorService).thenApplyAsync(result -> {
System.out.println("接受结果:"+result);
System.out.println("洗脸");
return "我洗完了";
});
//阻塞等待方法
String s = future.get();
System.out.println("最终结果:"+s);
/*
刷牙...
接受结果:我刷完了
洗脸
最终结果:我洗完了
*/
当两个任务都执行完毕之后,再执行当前任务。
//两个任务都完成,没有接收他们的结果,没有返回值
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);
//两个任务都完成 ,接收他们的结果并执行新任务,没有返回值
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);
//两个任务都完成 接收他们的结果并执行新任务 并返回当前任务的返回值。
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);
runAfterBoth示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return "我刷完了";
}, executorService);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("洗脸...");
return "我洗完了";
}, executorService);
future1.runAfterBothAsync(future2, () -> {
System.out.println("吃饭");
}, executorService);
/*
刷牙...
洗脸...
吃饭
*/
thenAcceptBoth示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return "我刷完了";
}, executorService);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("洗脸...");
return "我洗完了";
}, executorService);
future1.thenAcceptBothAsync(future2, (f1,f2) -> {
System.out.println("接受f1结果:"+f1);
System.out.println("接受f2结果:"+f2);
System.out.println("吃饭");
}, executorService);
/*
刷牙...
洗脸...
接受f1结果:我刷完了
接受f2结果:我洗完了
吃饭
*/
thenCombine示例
//创建一个线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("刷牙...");
return "我刷完了";
}, executorService);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("洗脸...");
return "我洗完了";
}, executorService);
CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (f1, f2) -> {
System.out.println("接受f1结果:" + f1);
System.out.println("接受f2结果:" + f2);
System.out.println("吃饭");
return "吃完了";
}, executorService);
String s = future3.get();
System.out.println("最终结果:"+s);
/*
刷牙...
洗脸...
接受f1结果:我刷完了
接受f2结果:我洗完了
吃饭
最终结果:吃完了
*/
只要两个任务完成一个,就会触发第三个任务的执行。
//接收某个任务执行完成的结果,有返回值.
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn
,Executor executor);
//接收某个任务执行完成的结果,无返回值.
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) ;
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action);
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor);
//不接收某个任务执行完成的结果,也无返回值.
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action);
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action) ;
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);