一 概述
在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过`get`方法阻塞或 者轮询的方式获得结果,但是这种方式不推荐使用。 CompletableFuture 和 FutureTask 同属于 Future 接口的实现类,都可以获取线程的执行结果。
二 代码实践
//自定义异步线程池,并且不存在返回值
CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
}, executor);
//使用JDK默认的线程池,并且不存在返回值
CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName());
});
//自定义异步线程池,并且存在返回值
CompletableFuture<Integer> futureE = CompletableFuture.supplyAsync(() -> 1, executor);
System.out.println(Thread.currentThread().getName() + "futureE.get() = " + futureE.get());
//自定JDK默认的线程池,并且存在返回值
CompletableFuture<Integer> futureJ = CompletableFuture.supplyAsync(() -> 1);
System.out.println(Thread.currentThread().getName() + "futureJ.get() = " + futureJ.get());
//whenComplete与exceptionally方法
//whenComplete可以处理正常和异常的计算结果,另一个方法为whenCompleteAsync
CompletableFuture<Integer> futureC = CompletableFuture.supplyAsync(() -> 10/0, executor).whenComplete((res, exception) -> {
System.out.println("res:" + res + "exception:" + exception);
}).exceptionally((exception)->{
//exceptionally处理异常情况
System.out.println("exception = " + exception);
//发生异常的时候可以设置返回的默认值
return 100;
});
System.out.println("futureC.get() = " + futureC.get());
/**
* whenComplete是执行当前任务的线程继续执行whenComplete的任务
* whenCompleteAsync是whenCompleteAsync执行的内容当作一个新的任务提交给线程池。
* 不以Async结尾的方法意味着与之前的任务使用同一个线程执行。
* 以Async结尾的方法意味着使用其他线程执行,当使用的线程池相同的时候也可能会被同一个线程选中执行。
**/
//handle方法
/**
* whenComplete 一样,可对结果做最后的处理(可处理异常),可改变返回值。
* 以Async和不以Async结尾任务的执行同whenComplete
*/
CompletableFuture<Integer> futureH = CompletableFuture.supplyAsync(()->10/0,executor).handleAsync((res,exception)->{
if (res != null) {
res += res;
}
if (exception != null) {
res = 100;
}
return res;
},executor);
System.out.println("futureH.get() = " + futureH.get());
/**
* thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前 任务的返回值。
* thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
* thenRun 方法:只要前面的任务执行完成,就开始执行thenRun,带有 Async 默认是异步执行的。同之前。 这些方法都要前置任务成功完成。
* Function<? super T,? extends U> T:上一个任务返回结果的类型 U:当前任务的返回值类型
*/
//线程串行化方法
CompletableFuture<Integer> futureP = CompletableFuture.supplyAsync(()->10,executor).thenApplyAsync((input)-> input*input,executor);
System.out.println("futureP = " + futureP.get());
CompletableFuture.supplyAsync(()->10,executor).thenAcceptAsync(res->{
System.out.println("res = " + res);
},executor);
CompletableFuture.supplyAsync(()->10,executor).thenRunAsync(new Thread(),executor);
/**
* 两个任务必须都完成,触发该任务。
* thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
* thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有 返回值。
* runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后, 处理该任务。
*/
//2个任务都要完成
CompletableFuture<Integer> futureOne = CompletableFuture.supplyAsync(()->10,executor);
CompletableFuture<String> futureTwo = CompletableFuture.supplyAsync(()->"String",executor);
CompletableFuture<String> future = futureOne.thenCombineAsync(futureTwo, (res1, res2) -> res1 + res2, executor);
System.out.println("future = " + future.get());
futureTwo.thenAcceptBothAsync(futureOne,(res1,res2)->{
System.out.println("res1:" + res1 + "res2:" +res2 );
},executor);
futureTwo.runAfterBothAsync(futureOne,new Thread(),executor);
/**
* 当两个任务中,任意一个 future 任务完成的时候,执行任务。
* applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
* acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
* runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值。
**/
CompletableFuture<Integer> futureThree = CompletableFuture.supplyAsync(()->100,executor);
CompletableFuture<Integer> futureAE = futureOne.applyToEitherAsync(futureThree, (res) -> res, executor);
System.out.println("futureAE = " + futureAE.get());
futureOne.acceptEitherAsync(futureThree,res->{
System.out.println("哈哈");
},executor);
futureThree.runAfterEitherAsync(futureOne,()->{
System.out.println("呼呼");
},executor);
//get()阻塞等待所有任务完成
CompletableFuture.allOf(future,futureAE).get();
//任意一个任务完成即可
Object o = CompletableFuture.anyOf(future, futureOne, futureTwo).get();
System.out.println("o = " + o.toString());
三 结果展示
pool-1-thread-1
ForkJoinPool.commonPool-worker-1
mainfutureE.get() = 1
mainfutureJ.get() = 1
res:nullexception:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
exception = java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
futureC.get() = 100
futureH.get() = 100
futureP = 100
res = 10
future = 10String
res1:Stringres2:10
futureAE = 10
o = 10String
呼呼
哈哈
注意
applyToEitherAsync中的两个任务的返回值要相同,否则会出现上图提示信息。
时间原因,暂时如此,后续再来整理,麻烦可以耐心等待。。。