用处:异步任务编排,JDK8提供。
底层涉及到线程池,用的是jdk的线程池,可以在启动的时候设置。
修改参数具体可以根据电脑的核心大小。
但是建议不要修改线程池的大小参数等等。新建一个线程池,方法调用的时候传递即可。
主要API
1. 异步任务的创建
runAsync
:运行一个异步任务,不返回结果。supplyAsync
:运行一个异步任务,返回结果。
2. 任务的组合
thenApply
:当一个CompletableFuture
完成时,应用一个函数转换结果。thenAccept
:当一个CompletableFuture
完成时,消费其结果。thenRun
:当一个CompletableFuture
完成时,运行一个 Runnable 任务。thenCombine
:当两个CompletableFuture
完成时,组合它们的结果。thenCompose
:当一个CompletableFuture
完成时,返回另一个CompletableFuture
。
在组合API中,每一个都会有其他变种的api
看名字可以得出结论
xxxAsync将会异步执行
重载方法xxxAsync可以指定执行的线程池
3. 异常处理
exceptionally
:处理任务执行中遇到的异常。handle
:无论任务是否正常完成,都可以处理结果或异常。
4. 结果获取
get
:阻塞并获取结果。join
:类似于get
,但不抛出检查异常。
API使用举例
开启异步任务,捕获异常,结果获取
假设你是小王,来到一家餐厅吃饭,主要经历的事情应该是这样的
- 坐下,叫来服务员点菜
- 点完菜,服务员将菜单给厨师,厨师开始做菜
- 厨师做好菜,装饭,上菜给小王吃
- 小王吃完,结账走人
对应到代码就是下面这样的。
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("小王来到餐厅,开始点菜了");
CompletableFuture<String> dish= CompletableFuture.supplyAsync(() -> {
log.info("开始做菜了");
return "番茄炒蛋做好了,上菜";
}).exceptionally((ex)->{
String message = ex.getMessage();
log.info(message);
return message;
});
System.out.println(dish.get());//注意,该方法会抛出异常检查
}
可以看到supplyAsync
开启了做菜这个异步任务,并且返回一个String。
与此对应的还有runAsync
这个方法,只不过该方法不需要返回值。
任务1->任务2
还是上面那个场景,只不过厨师在做菜的时候需要先配菜,才能将配菜做成菜品。
使用thenApply转换成代码如下
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("小王来到餐厅,开始点菜了");
CompletableFuture<String> dish= CompletableFuture.supplyAsync(() -> {
log.info("开始做菜了");
return "番茄炒蛋配菜";
}).thenApplyAsync((garnish)->{//将上一步配菜传递到这边
log.info("这是准备好的配菜{}",garnish);
return "成品菜";
}).exceptionally((ex)->{
String message = ex.getMessage();
log.info(message);
return message;
});
System.out.println(dish.get());
}
使用thenCompose转换成代码如下
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("小王来到餐厅,开始点菜了");
CompletableFuture<String> dish = CompletableFuture.supplyAsync(() -> {
log.info("开始做菜了");
return "番茄炒蛋配菜";
}).thenCompose((garnish) -> {
return CompletableFuture.supplyAsync(() -> {
log.info("这是准备好的配菜: " + garnish);
return "成品菜";
});
}).exceptionally((ex) -> {
String message = ex.getMessage();
log.info("遇到异常: " + message);
return "烹饪失败: " + message;
});
// 阻塞等待结果
String result = dish.get();
log.info("最终结果: " + result);
}
两者的区别在于,thenCompose是将一个CompletableFuture转换成另外一个。而thenApply是任务级别之间的传递。
任务1&任务2
thenCombine
方法用于当两个 CompletableFuture
都完成时,组合它们的结果。
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("小王来到餐厅,开始点菜了");
CompletableFuture<String> riceFuture = CompletableFuture.supplyAsync(() -> {
log.info("开始做饭");
return "蒸饭完成";
});
// 参数列表 supplier2,function
CompletableFuture<String> dishFuture = riceFuture.thenCombine(
CompletableFuture.supplyAsync(() -> {
log.info("开始做菜");
return "番茄炒蛋";
}),
(rice, dish) -> {
log.info("组合结果");
return rice + " 和 " + dish;
}
).exceptionally((ex) -> {
String message = ex.getMessage();
log.info("遇到异常: " + message);
return "烹饪失败: " + message;
});
// 阻塞等待结果
String result = dishFuture.get();
log.info("最终结果: " + result);
}