很多时候多个任务之间的业务逻辑上处理存在串行[依赖]、并行、聚合的关系。CompletableFuture是Future接口的增强,实现了对任务的编排能力。
CompletionStage接口:执行某一个阶段,可向下执行后续阶段。
使用demo:
CompletableFuture<String> future =CompletableFuture.supplyAsync(()‐>{
System.out.println("执行有返回值的异步任务");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello World";
});
//join()和get()方法都是用来获取CompletableFuture异步之后的返回值
String result=future.get();
System.out.println(result);
//当CompletableFuture的计算结果完成,可以执行特定的 Action。
future.whenComplete(new BiConsumer<String, Throwable>() {
@Override
public void accept(String t, Throwable action) {
System.out.println(t+" 执行完成!");
}
});
//抛出异常的时候,可以执行特定的Action。
future.exceptionally(new Function<Throwable, String>() {
@Override
public String apply(Throwable t) {
System.out.println("执行失败:"+t.getMessage());
return "异常xxxx";
}
}).join();
应用场景
依赖关系:
- thenApply() 把前面异步任务的结果,交给后面的Function
thenCompose()用来连接两个有依赖关系的任务,结果由第二个任务返回
and聚合关系:
thenCombine:任务合并,有返回值
- thenAccepetBoth:两个任务执行完成后,将结果交给thenAccepetBoth消耗,无返回值。
runAfterBoth:两个任务都执行完成后,执行下一步操作(Runnable)。
or聚合关系:
applyToEither:两个任务谁执行的快,就使用那一个结果,有返回值。
- acceptEither: 两个任务谁执行的快,就消耗那一个结果,无返回值。
- runAfterEither: 任意一个任务执行完成,进行下一步操作(Runnable)。
并行执行:
CompletableFuture类自己也提供了anyOf()和allOf()用于支持多个CompletableFuture 并行执行
使用案例:实现最优的“烧水泡茶”程序
对于烧水泡茶这个程序,一种最优的分工方案:用两个线程 T1 和 T2 来完成烧水泡茶程序, T1 负责洗水壶、烧开水、泡茶这三道工序,T2 负责洗茶壶、洗茶杯、拿茶叶三道工序,其中 T1 在执行泡茶这道工序时需要等待 T2 完成拿茶叶的工序。
public class CompletableFutureDemo2 {
public static void main(String[] args) {
//任务1:洗水壶‐>烧开水
CompletableFuture<Void> f1=CompletableFuture.runAsync(() ‐>{
System.out.println("T1:洗水壶...");
sleep(1, TimeUnit.SECONDS);
System.out.println("T1:烧开水...");
sleep(15, TimeUnit.SECONDS);
});
//任务2:洗茶壶‐>洗茶杯‐>拿茶叶
CompletableFuture<String> f2=CompletableFuture.supplyAsync(() ‐> {
System.out.println("T2:洗茶壶...");
sleep(1, TimeUnit.SECONDS);
System.out.println("T2:洗茶杯...");
sleep(2, TimeUnit.SECONDS);
System.out.println("T2:拿茶叶...");
sleep(1, TimeUnit.SECONDS);
return "龙井";
});
//任务3:任务1和任务2完成后执行:泡茶
CompletableFuture<String> f3 = f1.thenCombine(f2, (__, tf)‐>{
System.out.println("T1:拿到茶叶:"+tf);
System.out.println("T1:泡茶...");
return "上茶:"+tf;
});
//等待任务3执行结果
System.out.println(f3.join());
}