java8CompletableFuture⼊门使⽤教程详解所有⽅法附实例概览
1. CompletableFuture是java8引⼊的新类,该类实现了 Future 接⼝和 CompletionStage 接⼝,封装了future、forkjoin相关类来
执⾏异步,所以你还是可以像以前⼀样通过阻塞(get)或者轮询的⽅式获得结果,尽管这种⽅式不推荐使⽤。
2. CompletionStage 接⼝代表异步计算中的 不同阶段,以及如何 组合 这些计算阶段。
3. CompletableStage 接⼝中有 50 多个⽅法,可以对 CompletableStage 进⾏组合、计算,⽅法看似很多,但可以按功能对其分
类,⼤多数⽅法都有 3 种变体:
1. 不带 Async ⽅法:同步⽅法
2. 带 Async,只有⼀个参数:异步⽅法,使⽤默认的 ForkJoinPoolmonPool() 获取线程池
3. 带 Async,有两个参数:异步⽅法,且使⽤第⼆个参数指定的 ExecutorService 线程池
创建CompletableFuture对象
//⽐较特殊,他⼊参就是返回值,也就是说他可以⽤来执⾏需要其他返回值的异步任务。
public static <U> CompletableFuture<U> completedFuture(U value)
//⽆返回值,使⽤默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)
//⽆返回值,使⽤⾃定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
//有返回值,使⽤默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
//有返回值,使⽤⾃定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
/
/
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
复制代码
举例:
//supplyAsync⽅法⽆⼊参,但是返回⼀个String对象。此⽅法使⽤了默认的线程池执⾏异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
//长时间的计算任务
return "·00";
});
复制代码
在创建完CompletableFuture对象并且执⾏任务之后,还可以对结果或者异常等进⾏额外的操作或任务
下⾯将通过具体例⼦来展⽰各个⽅法的使⽤。
1.whenComplete* 和 exceptionally ⽅法
当原始的CompletableFuture任务执⾏完后,不管是否成功计算出结果,还是抛出异常,都会会执⾏ whenComplete* 或 exceptionally 的⽅法中的任务。
该操作执⾏完毕后:
会返回⼀个新的CompletableFuture对象
使⽤whenComplete*⽅法时,返回的新的CompletableFuture对象的返回结果和原始的CompletableFuture对象计算结果相同使⽤ exceptionally⽅法时,如果原始计算逻辑抛出异常,那么返回的 新的CompletableFuture对象 的返回结果由该⽅法的return值决定;如果原始计算逻辑没有抛出异常,那么返回的 新的CompletableFuture对象 的返回结果和原始计算逻辑返回的结果⼀致。有点绕,先不明⽩没关系,下⾯会有四个exceptionally实例解释这段话。
BiConsumer<T,U> 函数接⼝有两个参数,⽆返回值。
Function<T,R> 函数接⼝有⼀个输⼊参数,返回⼀个结果。
//⽆Async,同步处理正常计算结果或异常,使⽤执⾏任务的那个线程来执⾏该⽅法,所以这个⽅法是同步的。
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
//有Async,异步处理正常计算结果或异常,使⽤执⾏任务的那个线程池中的线程来执⾏该⽅法!所以这个⽅法是异步的。
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
//有Async,异步处理正常计算结果或异常,使⽤⾃定义线程池来执⾏该⽅法,所以这个⽅法是异步的。
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? superThrowable> action, Executor executor)
//处理异常。
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
复制代码
注意:当没有异常抛出来的时候,上⾯的Throwable参数为空!
举例:
计算逻辑:
private static Random random = new Random();
private static long time = System.currentTimeMillis();
public static int getMoreData(){
System.out.println("begin to start compute");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("end to compute, passed:" + System.currentTimeMillis());
Int(1000);
}
public static int throwException(){
System.out.println("准备抛出异常");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("抛了");
throw new RuntimeException("主动抛出异常");
}
复制代码
whenComplete:
//如果使⽤这段代码,则会是和当前线程同步执⾏
public static void main(String[] args) throws Exception{
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> getMoreData());
CompletableFuture<Integer> future2 = future.whenComplete((result, excetion) -> {
System.out.println("执⾏到whenComplete了,result:" + result);
System.out.println("执⾏到whenComplete了,exception:" + (excetion == null ? "⽆异常" : Class()));
});
System.out.println("执⾏到最后⼀段代码了,future result:" + ());
System.out.println("执⾏到最后⼀段代码了,future2 result:" + ());
}
> 打印执⾏结果:
begin to start compute
end to compute, passed:1551182552193
执⾏到whenComplete了,result:625
执⾏到whenComplete了,exception:⽆异常
执⾏到最后⼀段代码了,future result:625
执⾏到最后⼀段代码了,future2 result:625
>从打印结果可知,whenComplete使⽤原始的执⾏的任务的线程,所以可以看成是同步执⾏的,并且新的CompletableFuture对象的结果和原始的⼀致复制代码
whenCompleteAsync:
//如果使⽤这段代码,则会是和当前线程同步执⾏
public static void main(String[] args) throws Exception{
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> getMoreData());
future.whenCompleteAsync((result, exception) -> {
System.out.println("计算已执⾏完毕,result:" + result);
System.out.println("计算已执⾏完毕,exception:" + (excetion == null ? "⽆异常" : Class()));
});
System.out.println("执⾏到最后⼀段代码了,result:" + ());
}
> 打印执⾏结果:
begin to start compute
end to compute, passed:1551180611064
执⾏到最后⼀段代码了,result:323
执⾏到whenComplete了,result:323
执⾏到whenComplete了,exception:⽆异常
>从打印结果可知,whenCompleteAsync是异步执⾏的
复制代码
exceptionally⽐较复杂,需要通过4个实例才能真正明⽩:
/
/这段代码,由于会抛出异常,会先⾛whenCompleteAsync,然后再⾛exceptionally,⽽且是⽆法获取到返回值的。 public static void main(String[] args) throws Exception{
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> throwException());
future.whenCompleteAsync((result, exception) -> {
System.out.println("计算已执⾏完毕,result:" + result);
System.out.println("计算已执⾏完毕,exception:" + (exception == null ? "⽆异常" : Class()));
}).exceptionally(exception -> {
System.out.println("计算执⾏过程中发⽣了异常,exception:" + Class());
return 0;
});
System.out.println("执⾏到最后⼀段代码了,future result:" + ());
}
nextint()方法> 打印执⾏结果:
准备抛出异常
抛了
计算已执⾏完毕,result:null
计算已执⾏完毕,result:null
计算已执⾏完毕,exception:class urrent.CompletionException
计算已执⾏完毕,exception:class urrent.CompletionException
计算执⾏过程中发⽣了异常,exception:class urrent.CompletionException
计算执⾏过程中发⽣了异常,exception:class urrent.CompletionException
Exception in thread "main" urrent.ExecutionException: java.lang.RuntimeException: 主动抛出异常
at portGet(CompletableFuture.java:357)
at (CompletableFuture.java:1895)
at s.eapp.service.impl.Main.main(Main.java:69)
Caused by: java.lang.RuntimeException: 主动抛出异常
at s.eapp.service.impl.Main.throwException(Main.java:37)
at s.eapp.service.impl.Main.lambda$main$0(Main.java:44)
复制代码
//这⾥的打印结果是和上⾯类似的,可是为什么这次要获取新的CompletableFuture对象呢?看下⾯的exceptionally实例3后,再回来对⽐吧 public static void main(String[] args) throws Exception{
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> throwException());
CompletableFuture<Integer> future2 = future.whenCompleteAsync((result, exception) -> {
System.out.println("计算已执⾏完毕,result:" + result);
System.out.println("计算已执⾏完毕,exception:" + (exception == null ? "⽆异常" : Class()));
});
CompletableFuture<Integer> future3 = ptionally(exception -> {
System.out.println("计算执⾏过程中发⽣了异常,exception:" + Class());
return 0;
});
System.out.println("执⾏到最后⼀段代码了,future result:" + ());
//因为上⾯的执⾏过程中,已经抛出了异常了,那么下⾯的这两段代码是⽆法执⾏到的,
System.out.println("执⾏到最后⼀段代码了,future2 result:" + ());
System.out.println("执⾏到最后⼀段代码了,future3 result:" + ());
}
> 打印执⾏结果:
准备抛出异常
抛了
计算已执⾏完毕,result:null
计算已执⾏完毕,exception:class urrent.CompletionException
计算执⾏过程中发⽣了异常,exception:class urrent.CompletionException
Exception in thread "main" urrent.ExecutionException: java.lang.RuntimeException: 主动抛出异常
at portGet(CompletableFuture.java:357)
at (CompletableFuture.java:1895)
at s.eapp.service.impl.Main.main(Main.java:69)
Caused by: java.lang.RuntimeException: 主动抛出异常
at s.eapp.service.impl.Main.throwException(Main.java:37)
at s.eapp.service.impl.Main.lambda$main$0(Main.java:44)
复制代码
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论