执行CompletableFuture的多个thenAccept块的顺序是什么

时间:2016-06-20 08:44:12

标签: java java-8 completable-future

所以我有一个返回CompletableFuture的方法。在返回之前,此方法会添加一个thenAccept的块,该块在CompletableFuture完成后执行。

此方法的调用者还添加了另一个thenAccept块。显然,这可以继续多个链式调用。

执行CompletionStage调用返回的thenAccept的顺序是什么?是否保证是添加它们的顺序?如果没有,如何保证它们按照添加顺序执行?

PS:我根据自己对CompletableFuturearticle

的经验提出这个问题

1 个答案:

答案 0 :(得分:7)

您通过链接来建模完成阶段的依赖关系。如果您将两个操作AB链接到另一个操作C,则可以定义关系A → CB → C,但A之间没有任何关系和B因此,他们之间没有关系,包括没有排序关系,换句话说,你甚至不能假设一个人会追逐另一个,即

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    return "source";
});
base.thenAccept(s -> {
    System.out.println("entered first consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAccept(s -> {
    System.out.println("entered second consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving second consumer");
});

很可能打印出类似

的内容
entered first consumer in Thread[ForkJoinPool.commonPool-worker-1,5,main]
entered second consumer in Thread[main,5,main]
leaving second consumer
leaving first consumer

当然,虽然没有保证。

要强制实现两个消费者之间的依赖关系,您必须对其进行适当的链接,例如

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    return "source";
});
CompletableFuture<Void> next = base.thenAccept(s -> {
    System.out.println("entered first consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAcceptBoth(next, (s,ignored) -> {
    System.out.println("entered second consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving second consumer");
}).join();

在这里,第二个消费者被链接到basenext,以便从base接收结果,但是依赖于next的完成(您通常不会这样做)如果没有结果可以通过 - 如果您有这样的情况,也许您想重新考虑您的设计。)

或者,您可以将第一个Consumer转换为通过该值的Function,以便您可以通过thenApply将其链接,以允许链接另一个thenAccept阶段它。