CompletableFuture概述
①. 在Java8中,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合CompletableFuture的方法
②.它可能代表一个明确完成的Future,也有可能代表一个完成阶段(CompletionStage),它支持在计算完成以后触发一些函数或执行某些动作
③. 它实现了Future和CompletionStage接口
CompletableFuture创建方式
①. CompletableFuture 提供了四个静态方法来创建一个异步操作 runAsync方法不支持返回值
- supplyAsync可以支持返回值,我们一般用supplyAsync来创建
//runAsync方法不支持返回值
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
//supplyAsync可以支持返回值
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
- 没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同
CompletableFuture API
1:获得结果和触发计算(get、getNow、join、complete)
-
①. public T get( ) 不见不散(会抛出异常) 只要调用了get( )方法,不管是否计算完成都会导致阻塞
-
②. public T get(long timeout, TimeUnit unit) 过时不候
-
③. public T getNow(T valuelfAbsent):没有计算完成的情况下,给我一个替代结果计算完,返回计算完成后的结果、没算完,返回设定的valuelfAbsent
- ④. public T join( ):join方法和get( )方法作用一样,不同的是,join方法不抛出异常
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}
return 1;
});
//(1).public T get()不见不散(会抛出异常)
//System.out.println(future.get());
//(2).public T get(long timeout, TimeUnit unit) 过时不候2s后如果没有返回结果就报错
//System.out.println(future.get(2,TimeUnit.SECONDS));
//public T getNow(T valuelfAbsent)
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}
//没有计算完成的情况下,给我一个替代结果
//Integer now = future.getNow(3);
//这里停顿了3s,而我2s后就有结果了,所以可以正常拿到值 false获取到的值是1
//如果这里停顿1s,而我2s后才有结果,那么就不可以正常拿到值,true获取到的值是444
boolean flag = future.complete(444);
System.out.println(flag+"获取到的值是"+future.get());
2:对计算结果进行处理(thenApply、handle)
①. public <U> CompletableFuture<U> thenApply
计算结果存在依赖关系,这两个线程串行化
由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
②. public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
:
有异常也可以往下一步走,根据带的异常参数可以进一步处理
③. whenComplete:是执行当前任务的线程执行继续执行whenComplete的任务
④. whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}
return 1;
}).thenApply(s->{
System.out.println("-----1");
//如果加上int error=1/0; 由于存在依赖关系(当前步错,不走下一步),当前步骤有异常的话就叫停
//int error=1/0;
return s+1;
}).thenApply(s->{
System.out.println("-----2");
return s+2;
}).whenComplete((v,e)->{
if(e==null){
System.out.println("result-----"+v);
}
}).exceptionally(e->{
e.printStackTrace();
return null;
});
System.out.println(Thread.currentThread().getName()+"\t"+"over....");
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 20, 1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(50), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
System.out.println(CompletableFuture.supplyAsync(() -> {
return 1;
}).handle((f,e) -> {
System.out.println("-----1");
return f + 2;
}).handle((f,e) -> {
System.out.println("-----2");
//如果这里异常了,handle方法依旧可以继续执行下去
/*
-----1
-----2
-----3
null
java.util.concurrent.CompletionException: java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
at java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:824)
at java.util.concurrent.CompletableFuture.uniHandleStage(CompletableFuture.java:834)
at java.util.concurrent.CompletableFuture.handle(CompletableFuture.java:2155)
at com.atguigu.juc.api.CompletableFutureApiDemo.main(CompletableFutureApiDemo.java:19)
Caused by: java.lang.NullPointerException
at com.atguigu.juc.api.CompletableFutureApiDemo.lambda$main$3(CompletableFutureApiDemo.java:21)
at java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:822)
... 3 more
* */
int error=1/0;
return f + 3;
}).handle((f,e) -> {
System.out.println("-----3");
return f + 4;
}).whenComplete((v, e) -> {
if (e == null) {
System.out.println("----result: " + v);
}
}).exceptionally(e -> {
e.printStackTrace();
return null;
}).join());
threadPoolExecutor.shutdown();
3:对计算结果进行消费(thenRun、thenAccept、thenApply)
①. thenRun(Runnable runnable)
任务A执行完执行B,并且B不需要A的结果
②. CompletableFuture<Void> thenAccept(Consumer<? super T> action)
任务A执行完成执行B,B需要A的结果,但是任务B无返回值
③. public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
任务A执行完成执行B,B需要A的结果,同时任务B有返回值
CompletableFuture.supplyAsync(() -> {
return 1;
}).thenApply(f -> {
return f+2;
}).thenApply(f -> {
return f+3;
}).thenAccept(r -> System.out.println(r));
// 任务A执行完执行B,并且B不需要A的结果
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {}).join());
// 任务A执行完成执行B,B需要A的结果,但是任务B无返回值
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {}).join());
// 任务A执行完成执行B,B需要A的结果,同时任务B有返回值
System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB").join());
注意:
线程串行化方法带了Async的方法表示的是:会重新在线程池中启动一个线程来执行任务
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)
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 CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
4: 对计算速度进行选用(applyToEither、acceptEither、runAfterEither)
①. public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
这个方法表示的是,谁快就用谁的结果,类似于我们在打跑得快,或者麻将谁赢了就返回给谁
//这个方法表示的是,谁快就用谁的结果,类似于我们在打跑得快,或者麻将谁赢了就返回给谁
//public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn);
//下面这个在第一个中停留1s,在第二种停留2s,返回的结果是1
System.out.println(CompletableFuture.supplyAsync(() -> {
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace();}
return 1;
}).applyToEither(CompletableFuture.supplyAsync(() -> {
try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) {e.printStackTrace();}
return 2;
}), r -> {
return r;
}).join());
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
②. 两任务组合,一个完成
- applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
- acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
- runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值
5:对计算结果进行合并(thenCombine、thenAcceptBoth、runAfterBoth)
①. public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
//public <U,V> CompletableFuture<V> thenCombine
//(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn)
//两个CompletionStage任务都完成后,最终把两个任务的结果一起交给thenCombine来处理
//先完成的先等着,等待其他分支任务
System.out.println(CompletableFuture.supplyAsync(() -> {
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
return 20;
}), (r1, r2) -> {
return r1 + r2;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
return 30;
}), (r3, r4) -> {
return r3 + r4;
}).join());
System.out.println(CompletableFuture.supplyAsync(() -> {
return 10;
}).thenCombine(CompletableFuture.supplyAsync(() -> {
return 20;
}), (r1, r2) -> {
return r1 + r2;
}).join());