异步编程八:CompletableFuture异步编程任务编排 - 2

69 阅读4分钟

编排两个非依赖关系的异步任务 - 两任务组合-两个任务任一完成执行

public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action)
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,
                                                       Executor executor)


public CompletableFuture<Void> acceptEither(
              CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(
              CompletionStage<? extends T> other, Consumer<? super T> action)}
public CompletableFuture<Void> acceptEitherAsync(
              CompletionStage<? extends T> other, Consumer<? super T> action,Executor executor)}

public <U> CompletableFuture<U> applyToEither(
              CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
              CompletionStage<? extends T> other, Function<? super T, U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(
        CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor)

当两个任务中,任意一个future任务完成的时候,执行任务。

  • applyToEither 两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。
  • acceptEither 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
  • runAfterEither 两个任务有一个执行完成,不需要获取future的结果,处理任务,也没有返回值。

RunAfterEitherAsync()

runAfterEither 两个任务有一个执行完成,不需要获取future的结果,处理任务,也没有返回值。

public class CompletableFutureRunAfterEitherAsync {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        System.out.println("main start ...");
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return "hello";
        }, executor);
        future1.runAfterEitherAsync(future2, () -> {
            System.out.println("任务3 启动了....");
        }, executor);
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
开启异步任务1...
main end ...
任务3 启动了....
开启异步任务2...

我们可以看到,任务1执行完成后,任务3不需要等待任务2执行完成,即可启动任务3。但是使用runAfterEitherAsync不能感知任务的返回值,自身也无返回值。

AcceptEither()

acceptEither 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。

public class CompletableFutureAcceptEither {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        System.out.println("main start ...");

        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return 10;
        }, executor);
        future1.acceptEitherAsync(future2, (res) -> {
            System.out.println("任务3 启动了...., 任务结果是:" + res);
        }, executor);

        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
开启异步任务1...
main end ...
任务3 启动了...., 任务结果是:5
开启异步任务2...

可以看到,可以获取任务1的执行结果,但不返回执行结果。

ApplyToEither()

applyToEither 两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。

public class CompletableFutureApplyToEither {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        System.out.println("main start ...");
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("开启异步任务1...");
            int i = 10 / 2;
            return i;
        }, executor);

        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("开启异步任务2...");
            return 10;
        }, executor);

        CompletableFuture<String> stringCompletableFuture = future1.applyToEitherAsync(future2, (res) -> {
            System.out.println("任务3 启动了...., 上个任务结果是:" + res);
            return "我是任务三的返回值, 上个任务的执行结果是:" + res;
        }, executor);
        System.out.println(stringCompletableFuture.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
开启异步任务1...
任务3 启动了...., 上个任务结果是:5
我是任务三的返回值, 上个任务的执行结果是:5
main end ...
开启异步任务2...

编排多个非依赖关系的异步任务

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
  • allOf:等待所有任务完成
  • anyOf: 只要有一个任务完成

AllOf

allOf:等待所有任务完成

public class CompletableFutureAllOf {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        System.out.println("main start ...");
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片...");
            return "图片地址";
        }, executor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性...");
            return "黑色 256G";
        }, executor);

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品品牌...");
            return "苹果手机";
        }, executor);

        CompletableFuture<Void> future = CompletableFuture.allOf(future1, future2, future3);
        future.get();//等待索引结果完成
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
查询商品图片...
查询商品属性...
查询商品品牌...
main end ...

注:如果不使用future.get()阻塞,若其中一个任务执行时间较长,则可能会丢失任务信息。

AnyOf

public class CompletableFutureAnyOf {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(5);

        System.out.println("main start ...");
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片...");
            return "图片地址";
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性...");
            return "黑色 256G";
        }, executor);
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品品牌...");
            return "苹果手机";
        }, executor);
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(future1, future2, future3);
        System.out.println("第一个执行成功的数据:" + objectCompletableFuture.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
查询商品图片...
查询商品属性...
第一个执行成功的数据:图片地址
main end ...
查询商品品牌...

实战案例

业务背景: 在电商项目的售后业务中,当客服接收到用户的售后申请时,需要进行一系列操作,包括查询订单信息、查询 ERP 中的商品信息、查询用户信息,以及创建售后工单。

public CompletableFuture<Void> processAfterSalesRequest(String orderId, String customerId) {
    CompletableFuture<Order> orderFuture = CompletableFuture.supplyAsync(() -> getOrderInfo(orderId));
    CompletableFuture<Inventory> inventoryFuture = CompletableFuture.supplyAsync(() -> getInventoryInfo(orderId));
    CompletableFuture<User> userFuture = CompletableFuture.supplyAsync(() -> getUserInfo(customerId));

    return CompletableFuture.allOf(orderFuture, inventoryFuture, userFuture)
        .thenApplyAsync(ignored -> {
            Order order = orderFuture.join();
            Inventory inventory = inventoryFuture.join();
            User user = userFuture.join();

            // 创建售后工单
            createAfterSalesTicket(order, inventory, user);

            return null;
        });
}

private Order getOrderInfo(String orderId) {
    // 查询订单信息的逻辑
    // ...
    return order;
}

private Inventory getInventoryInfo(String orderId) {
    // 查询ERP中商品信息的逻辑
    // ...
    return inventory;
}

private User getUserInfo(String customerId) {
    // 查询用户信息的逻辑
    // ...
    return user;
}

private void createAfterSalesTicket(Order order, Inventory inventory, User user) {
    // 创建售后工单的逻辑
    // ...
}

在上述代码中,我们使用CompletableFuture.supplyAsync()  方法分别查询订单信息、ERP 中的商品信息和用户信息,然后使用CompletableFuture.allOf()  方法等待所有查询任务完成。完成后,我们可以通过join()  方法获取各个查询任务的结果,并将结果传递给createAfterSalesTicket()  方法来创建售后工单。