Lambda从入门到精通之三十五 CompletableFuture异步编程 acceptEither方法使用详解

CompletableFuture的acceptEither方法返回一个新的CompletionStage,当此两个任务中的任何一个正常完成时,将使用相应的结果作为所提供操作的参数来执行定义的Action,执行的Action没有返回值。

我们先来看一个demo,两个输出任务,哪个先完成,就输出哪个任务的结果

/**
 * 使用CompletableFuture异步编程 消费计算结果
 * @author www.itzhimei.com
 */
public class FutureTest_8 {

    public static void main(String[] args) {

        //执行10次两个输出任务
        for(int i=0; i<10; i++) {
            CompletableFuture.supplyAsync(()->"Test Task 1")
                    .acceptEither(CompletableFuture.supplyAsync(()->"Test Task 2"), System.out::println);
        }
        /* 输出
        Test Task 1
        Test Task 2
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
         */

    }

}

从结果来看任务1输出了9次,任务2输出了1次,因为从程序的执行顺序上,任务1确实是先执行的,是比较有优势的,当然我们可以对代码做一些小小的改动来检查acceptEither方法是不是二选一,先返回的先执行。

import java.util.concurrent.CompletableFuture;

/**
 * 使用CompletableFuture异步编程 消费计算结果
 * @author www.itzhimei.com
 */
public class FutureTest_8 {

    public static void main(String[] args) throws Exception {

        //执行10次两个输出任务
        for(int i=0; i<10; i++) {
            CompletableFuture.supplyAsync(()->"Test Task 1")
                    .acceptEither(CompletableFuture.supplyAsync(()->"Test Task 2"), System.out::println).join();
        }
        /* 输出
        Test Task 1
        Test Task 2
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
        Test Task 1
         */

        System.out.println("==================================================");

        //执行10次两个输出任务
        for(int i=0; i<10; i++) {
            CompletableFuture.supplyAsync(()->FutureTest_8.getTaskResult(1000, "Test Task 1"))
                    .acceptEither(CompletableFuture.supplyAsync(()->FutureTest_8.getTaskResult(500, "Test Task 2")), System.out::println).join();
        }
        /* 输出
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
        Test Task 2
         */

    }

    public static String getTaskResult(long sleepTime, String task) {
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return task;
    }

}

我们改造后的代码,加入了计算延时,第一个任务是1秒延时,第二个任务是0.5秒延时,所以程序每次都是用了任务2的结果进行输出。

CompletableFuture除了提供了acceptEither方法,还提供了两个异步方法acceptEitherAsync,一个是使用默认线程池进行异步计算,一个是使用自定义线程池进行异步计算。
CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) 
CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action) 
CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super  T> action, Executor executor)