当我们想第一个异步任务执行完成后,还需要做其他的事情。我们的
CompletableFuture提供了计算完成时回调方法,whenComplete、whenCompleteAsync、exceptionally等接口。
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
whenComplete 可以处理正常和异常的计算结果,exceptionally: 处理异常情况。
whenComplete和whenCompleteAsync 的区别是whenComplete 是执行当前任务的线程继续执行whenComplete的任务。
whenCompleteAsync: 是把whenCompleteAsync的任务继续提交给线程池来进行执行。
whenCompleteAsync
public class CompletableFutureWhenCompleteAsync {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
System.out.println("main start ...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 2;
return i;
}, executor).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
});
System.out.println("获取异步任务返回值:" + future.get());
System.out.println("main end ...");
executor.shutdown();
}
}
执行结果:
main start ...
开启异步任务...
异步任务完成了,执行结果是:5 异常是:null
获取异步任务返回值:5
main end ...
如果异步任务出现了异常,可以通过exc打印异常,我们在程序中设置一个运行时异常 ,如下:
public class CompletableFutureWhenCompleteAsync1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
System.out.println("main start ...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 0;
return i;
}, executor).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
});
System.out.println("获取异步任务返回值:" + future.get());
System.out.println("main end ...");
executor.shutdown();
}
}
执行结果:
main start ...
开启异步任务...
异步任务完成了,执行结果是:null 异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1908)
at com.qjw.thread.CompletableFutureWhenCompleteAsync1.main(CompletableFutureWhenCompleteAsync1.java:24)
Caused by: java.lang.ArithmeticException: / by zero
at com.qjw.thread.CompletableFutureWhenCompleteAsync1.lambda$main$0(CompletableFutureWhenCompleteAsync1.java:19)
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1604)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:750)
exceptionally
whenComplete虽然可以得到异常信息,但是无法修改结果,exceptionally可以感知异常,同时可以返回默认值。
public class CompletableFutureWhenExceptionally {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(5);
System.out.println("main start ...");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("开启异步任务...");
int i = 10 / 0;
return i;
}, executor).whenCompleteAsync((res, exc) -> {
System.out.println("异步任务完成了,执行结果是:" + res + " 异常是:" + exc);
}).exceptionally(throwable -> {
System.out.println("进入了异常处理,捕获了" + throwable.getMessage() + "异常");
return 5;
});
System.out.println("获取异步任务返回值:" + future.get());
System.out.println("main end ...");
executor.shutdown();
}
}
执行结果:
main start ...
开启异步任务...
异步任务完成了,执行结果是:null 异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
进入了异常处理,捕获了java.lang.ArithmeticException: / by zero异常
获取异步任务返回值:5
main end ...
我们可以看到,通过exceptionally可以捕获异步任务抛出来的异常信息,并对异常进行处理,并可以将处理结果返回。