简体   繁体   English

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

[英]What is the order in which multiple thenAccept blocks of a CompletableFuture are executed

So I have a method that returns a CompletableFuture . 所以我有一个返回CompletableFuture的方法。 Before returning, this method adds a block with thenAccept which is executed after the CompletableFuture completes. 在返回之前,此方法添加一个带有thenAccept的块,该块在CompletableFuture完成后执行。

The caller of this method also adds another block with thenAccept . 此方法的调用者还使用thenAccept添加另一个块。 Obviously this can go on with multiple chained calls. 显然,这可以继续多个链式调用。

In what order are the CompletionStage returned by the thenAccept invocations executed? 执行thenAccept调用返回的CompletionStage顺序是什么? Is it guaranteed to be the order in which they are added? 是否保证是添加它们的顺序? If not, how can one guarantee that they are executed in the order in which they are added? 如果没有,如何保证它们按照添加顺序执行?

PS: I am asking this based on my own experience with CompletableFuture and this article PS:我根据自己对CompletableFuture本文的经验提出这个问题

You are modelling the dependencies of completion stages by chaining them. 您通过链接它们来建模完成阶段的依赖关系。 If you chain two actions A and B to another action C , you define the relationships A → C and B → C , but no relationship between A and B and therefore, there is no relationship, including no ordering relationship, between them, in other words, you can't even assume that one will run after the other, ie 如果将两个动作AB到另一个动作C ,则定义关系A → CB → C ,但AB之间没有关系,因此,它们之间没有关系,包括没有排序关系,在其他言语,你甚至不能假设一个人会追逐另一个,即

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");
});

will very likely print something like 很可能打印出类似的东西

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

Though, of course, there is no guaranty about it. 当然,虽然没有保证。


To enforce your dependency between the two consumers, you have to chain them appropriately, eg 要强制实现两个消费者之间的依赖关系,您必须适当地链接它们,例如

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();

Here, the second consumer is chained to base and next , to receive the result from base , but depend on next 's completion (which you normally wouldn't require if there is no result to pass—maybe you want to rethink your design, if you have such a scenario). 在这里,第二个消费者被链接到basenext ,以便从base接收结果,但是依赖于next的完成(如果没有结果通常你通常不会要求 - 也许你想重新考虑你的设计,如果你有这样的场景)。

Alternatively, you may convert the first Consumer to a Function which passes through the value, so you can chain it via thenApply , to allow chaining another thenAccept stage to it. 或者,您可以将第一个Consumer转换为一个通过该值的Function ,这样您就可以通过thenApply链接它,以允许链接另一个thenAccept接受它的阶段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM