异步编程七:CompletableFuture异步编程任务编排

78 阅读4分钟

异步任务编排

编排有依赖关系的异步任务 thenCompose()

我们先有future1,然后和future2组成一个链:future1 -> future2,然后又组合了future3,形成链:future1 -> future2 -> future3。这里有个隐藏的点:future1、future2、future3它们完全没有数据依赖关系,我们只不过是聚合了它们的结果。

写法一:

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

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

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 第一个Future实例结果
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future1开始...");
            return "Hello";
        }, executor).thenCompose(result1 -> CompletableFuture.supplyAsync(() -> {
            // 将上一个Future实例结果传到这里
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future2开始..., 第一个实例结果:" + result1);
            return result1 + " World";
        }, executor)).thenCompose(result12 -> CompletableFuture.supplyAsync(() -> {
            // 将第一个和第二个实例结果传到这里
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future3开始..., 第一第二个实现聚合结果:" + result12);
            String targetResult = result12 + ", I am austin!";
            System.out.println("最终输出结果:" + targetResult);
            return targetResult;
        }, executor));

        System.out.println("获取异步任务返回值:" + future.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

写法二:

public class CompletableFutureWhenThenCompose1 {

    private static ExecutorService executor = Executors.newFixedThreadPool(5);


    public static void main(String[] args) throws ExecutionException, InterruptedException {

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

        CompletableFuture<String> future = future1()
                .thenCompose(CompletableFutureWhenThenCompose1::future2)
                .thenCompose(CompletableFutureWhenThenCompose1::future3);

        System.out.println("获取异步任务返回值:" + future.get());
        System.out.println("main end ...");

        executor.shutdown();
    }

    public static CompletableFuture<String> future1() {
        return CompletableFuture.supplyAsync(() -> {
            // 第一个Future实例结果
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future1开始...");
            return "Hello";
        }, executor);
    }

    public static CompletableFuture<String> future2(String result1) {
        return CompletableFuture.supplyAsync(() -> {
            // 将上一个Future实例结果传到这里
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future2开始..., 第一个实例结果:" + result1);
            return result1 + " World";
        }, executor);
    }

    public static CompletableFuture<String> future3(String result12) {
        return CompletableFuture.supplyAsync(() -> {
            // 将第一个和第二个实例结果传到这里
            System.out.println("thread name:" + Thread.currentThread().getName() + " 执行future3开始..., 第一第二个实现聚合结果:" + result12);
            String targetResult = result12 + ", I am austin!";
            System.out.println("最终输出结果:" + targetResult);
            return targetResult;
        }, executor);
    }
}

执行结果:

main start ...
thread name:pool-1-thread-1 执行future1开始...
thread name:pool-1-thread-2 执行future2开始..., 第一个实例结果:Hello
thread name:pool-1-thread-3 执行future3开始..., 第一第二个实现聚合结果:Hello World
最终输出结果:Hello World, I am austin!
获取异步任务返回值:Hello World, I am austin!
main end ...

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

我们先有future1和future2,然后根据future1和future2的结果,组合成future3,形成链:future1 和future2 -> future3。

public <U,V> CompletionStage<V> thenCombine(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletionStage<V> thenCombineAsync(CompletionStage<? extends U> other,
         BiFunction<? super T,? super U,? extends V> fn,Executor executor);         

public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action)
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action, Executor executor)


public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action)}
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action) }
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,
                                                     Executor executor)}

两个任务必须都完成,触发该任务。

  • runAfterBoth 不可以获取两个任务的返回值,并不可以将任务三结果返回;
  • thenAcceptBoth 可以获取两个任务的返回值,并不可以将任务三结果返回;
  • thenCombine 可以获取两个任务的返回值,并可以将任务三结果返回。

runAfterBoth()

runAfterBoth 不可以获取两个任务的返回值,并不可以将任务三结果返回;

public class CompletableFutureRunAfterBoth {
    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("执行future1开始...");
            return "Hello";
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行future2开始...");
            return "World";
        }, executor);

        CompletableFuture<Void> future = future1.runAfterBoth(future2, () -> {
            System.out.println("获取到future1、future2聚合结果:" + null);
        });

        System.out.println("获取异步任务返回值:" + future.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
执行future1开始...
执行future2开始...
获取到future1、future2聚合结果:null
获取异步任务返回值:null
main end ...

thenAcceptBoth()

thenAcceptBoth 可以获取两个任务的返回值,并不可以将任务三结果返回;

public class CompletableFutureThenAcceptBoth {
    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("执行future1开始...");
            return "Hello";
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行future2开始...");
            return "World";
        }, executor);

        CompletableFuture<Void> future = future1.thenAcceptBoth(future2,  (result1, result2) -> {
            String result = result1 + " " + result2;
            System.out.println("获取到future1、future2聚合结果:" + result);
        });

        System.out.println("获取异步任务返回值:" + future.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
执行future1开始...
执行future2开始...
获取到future1、future2聚合结果:Hello World
获取异步任务返回值:null
main end ...

thenCombine()

thenCombine 可以获取两个任务的返回值,并可以将任务三结果返回。

public class CompletableFutureWhenThenCombine {
    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("执行future1开始...");
            return "Hello";
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行future2开始...");
            return "World";
        }, executor);

        CompletableFuture<String> future = future1.thenCombine(future2, (result1, result2) -> {
            String result = result1 + " " + result2;
            System.out.println("获取到future1、future2聚合结果:" + result);
            return result;
        });

        System.out.println("获取异步任务返回值:" + future.get());
        System.out.println("main end ...");

        executor.shutdown();
    }
}

执行结果:

main start ...
执行future1开始...
执行future2开始...
获取到future1、future2聚合结果:Hello World
获取异步任务返回值:Hello World
main end ...