JDK8-11-CompletableFuture(5)- thenCompose 方法使用

承接上文: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线程处于空闲状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值