JUC并发编程—— CompletableFuture 实现异步回调
1、CompletableFuture
异步回调
异步回调指的是:在发起一个异步任务的同时指定一个函数,在异步任务完成时会自动的调用这个函数,这个函数就是回调函数。
CompletableFuture
Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。
使用 Future 获得异步执行结果时,要么调用阻塞方法get(),要么轮询看isDone()是否为true,这两种方法都不是很好,因为主线程也会被迫等待。
从Java 8开始引入了 CompletableFuture,它针对 Future 做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法,CompletableFuture 是 Future 的实现类。一个completableFuture对象代表着一个任务
CompletableFuture 的优点是:
- 异步任务结束时,会自动回调某个对象的方法;
- 异步任务出错时,会自动回调某个对象的方法;
- 主线程设置好回调后,不再关心异步任务的执行。
2、实现异步回调
2.1、异步任务
创建一个没有返回值的异步任务:
public class Demo01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//runAsync 执行一个异步任务,没有返回值
CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" ->runAsync->void");
});
//获取异步任务的结果
future.get();
}
}
runAsync表示创建无返回值的异步任务,该方法有一个重载版本,可以指定执行异步任务的Executor实现,如果不指定,默认使用 ForkJoinPool.commonPool()。
创建一个有返回值的异步任务:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" ->supplyAsync->Integer");
return 1024;
});
supplyAsync表示创建有返回值的异步任务,该方法有一个重载版本,可以指定执行异步任务的Executor实现,如果不指定,默认使用 ForkJoinPool.commonPool()。
2.2、异步回调
异步回调
创建异步任务执行完后的回调方法:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" ->supplyAsync->Integer");
//如果任务正常执行返回1024
return 1024;
});
//回调函数
CompletableFuture<Integer> whenComplete = future.whenComplete((t,u)->{
//打印两个参数
System.out.println("t->"+t);
System.out.println("u->"+u);
}).exceptionally((e)->{
System.out.println(e.getMessage());
//如果任务执行异常则返回500
return 500;
});
System.out.println(whenComplete.get());//获取异步任务的结果
whenComplete() :当某个任务执行完成后执行的回调方法,当CompletableFuture完成计算结果时对结果进行处理,或者当CompletableFuture产生异常的时候对异常进行处理。
whenComplete() 源码:
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(asyncPool, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return uniWhenCompleteStage(screenExecutor(executor), action);
}
whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。
BiConsumer 可以接收两个参数:
exceptionally方法指定某个任务执行异常时执行的回调方法,会将抛出异常作为参数传递到回调方法中,如果该任务正常执行则exceptionally方法返回的result就是该任务正常执行的结果。
查看上面任务正常执行时,回调函数的执行结果和参数的输出:
查看任务异常执行时,两个参数的输出:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" ->supplyAsync->Integer");
int i = 10 / 0;
return 1024;
});
whenComplete会将异步任务执行结果或者执行期间抛出的异常传递给回调方法,
如果任务正常执行:get方法输出正常执行结果,异常输出为null
如果任务执行出现异常:get方法输出异常执行结果,并打印异常信息,无正常结果