承接上文:https://blog.csdn.net/sql2008help/article/details/127345292
JDK8-11-CompletableFuture(5)- thenCompose 方法使用
假设餐厅新招了一名服务员,原来由厨师打饭现在改成服务员,步骤如下:
1.顾客进入餐厅
2.顾客开始点餐
3.厨师按照顾客所选菜品开始炒菜
4.服务员打饭
5.顾客开始吃饭
程序模拟如下:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SupplyAsyncTest02 {
public static void main(String[] args) {
PrintTool.printTimeAndThread("顾客进入餐厅。。。");
PrintTool.printTimeAndThread("顾客开始点餐。。。");
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("厨师开始炒菜。。。");
PrintTool.sleep(500);
CompletableFuture<String> waiterCF = CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("服务员开始打饭。。。");
PrintTool.sleep(200);
return "米饭";
});
return String.format("番茄炒蛋+%s", waiterCF.join());
});
PrintTool.printTimeAndThread("顾客玩手机中。。。");
try {
PrintTool.printTimeAndThread(String.format("顾客开始吃%s", cf.get()));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
执行结果:
如下所示,厨师和服务员的工作分为两个线程执行
1665905842727 | 1 | main | 顾客进入餐厅。。。
1665905842727 | 1 | main | 顾客开始点餐。。。
1665905842871 | 1 | main | 顾客玩手机中。。。
1665905842871 | 14 | ForkJoinPool.commonPool-worker-1 | 厨师开始炒菜。。。
1665905843384 | 15 | ForkJoinPool.commonPool-worker-2 | 服务员开始打饭。。。
1665905843623 | 1 | main | 顾客开始吃番茄炒蛋+米饭
虽然这种写法可以完成本例的工作,但是代码存在嵌套,而且 CompletableFuture 已经提供API用来连接两个异步任务
thenCompose 方法使用
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SupplyAsyncTest03 {
public static void main(String[] args) {
PrintTool.printTimeAndThread("顾客进入餐厅。。。");
PrintTool.printTimeAndThread("顾客开始点餐。。。");
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("厨师开始炒菜。。。");
PrintTool.sleep(500);
return "番茄炒蛋";
}).thenCompose(dish -> CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("服务员开始打饭。。。");
PrintTool.sleep(200);
return dish + "+米饭";
}));
PrintTool.printTimeAndThread("顾客玩手机中。。。");
try {
PrintTool.printTimeAndThread(String.format("顾客开始吃%s", cf.get()));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行结果:
1665909018391 | 1 | main | 顾客进入餐厅。。。
1665909018392 | 1 | main | 顾客开始点餐。。。
1665909018508 | 14 | ForkJoinPool.commonPool-worker-1 | 厨师开始炒菜。。。
1665909018508 | 1 | main | 顾客玩手机中。。。
1665909019017 | 15 | ForkJoinPool.commonPool-worker-2 | 服务员开始打饭。。。
1665909019247 | 1 | main | 顾客开始吃番茄炒蛋+米饭
Compose 意思为组成,thenCompose 意思为一个任务执行完后再执行下一个任务,thenCompose方法接收的入参为 Function,Function入参为上一个任务的结果(即dish),出参为 CompletionStage 的子类,此例中为 CompletableFuture
public <U> CompletableFuture<U> thenCompose(
Function<? super T, ? extends CompletionStage<U>> fn) {
return uniComposeStage(null, fn);
}
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
}
thenComposeAsync 方法
下面假设 服务员A开始打饭时,临时接到电话要去做其他更重要的事情,服务员A将打饭任务交给服务员B:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class SupplyAsyncTest03_2 {
public static void main(String[] args) {
PrintTool.printTimeAndThread("顾客进入餐厅。。。");
PrintTool.printTimeAndThread("顾客开始点餐。。。");
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("厨师开始炒菜。。。");
PrintTool.sleep(500);
return "番茄炒蛋";
}).thenComposeAsync(dish -> {
PrintTool.printTimeAndThread("服务员A准备盛饭,突然接到电话要去做其他事情,他将打饭任务交给服务员B。。。");
return CompletableFuture.supplyAsync(() -> {
PrintTool.printTimeAndThread("服务员B开始打饭。。。");
PrintTool.sleep(200);
return dish + "+米饭";
});
});
PrintTool.printTimeAndThread("顾客玩手机中。。。");
try {
PrintTool.printTimeAndThread(String.format("顾客开始吃%s", cf.get()));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行结果:
1666499691103 | 1 | main | 顾客进入餐厅。。。
1666499691103 | 1 | main | 顾客开始点餐。。。
1666499691289 | 14 | ForkJoinPool.commonPool-worker-1 | 厨师开始炒菜。。。
1666499691290 | 1 | main | 顾客玩手机中。。。
1666499691795 | 14 | ForkJoinPool.commonPool-worker-1 | 服务员A准备盛饭,突然接到电话要去做其他事情,他将打饭任务交给服务员B。。。
1666499691796 | 15 | ForkJoinPool.commonPool-worker-2 | 服务员B开始打饭。。。
1666499692033 | 1 | main | 顾客开始吃番茄炒蛋+米饭
thenComposeAsync 会在当前调用方法的任务上开启一个新的任务,这里指 “服务员A准备盛饭,突然接到电话要去做其他事情,他将打饭任务交给服务员B。。。” 这件事,虽然这里厨师炒菜和服务员A交接任务都是 ForkJoinPool.commonPool-worker-1 线程执行,但实际它们是两个任务,这是由于 服务员A交接任务前厨师已经炒完了菜,所以 ForkJoinPool.commonPool-worker-1线程处于空闲状态