执行CompletableFuture的多个thenAccept块的顺序是什么 [英] What is the order in which multiple thenAccept blocks of a CompletableFuture are executed
问题描述
所以我有一个返回 CompletableFuture
的方法。在返回之前,此方法添加一个块 thenAccept
,该块在 CompletableFuture
完成后执行。
So I have a method that returns a CompletableFuture
. Before returning, this method adds a block with thenAccept
which is executed after the CompletableFuture
completes.
此方法的调用者还添加了另一个块 thenAccept
。显然,这可以继续多个链式调用。
The caller of this method also adds another block with thenAccept
. Obviously this can go on with multiple chained calls.
<$ c>返回 CompletionStage
的顺序$ c> thenAccept 执行调用?是否保证是添加它们的顺序?如果没有,如何保证它们按照添加顺序执行?
In what order are the CompletionStage
returned by the thenAccept
invocations executed? 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:我根据自己的经验询问这个 CompletableFuture
此文章
PS: I am asking this based on my own experience with CompletableFuture
and this article
推荐答案
您正在通过链接来建模完成阶段的依赖关系。如果您将两个操作 A
和 B
链接到另一个操作 C
,您定义关系 A→C
和 B→C
,但之间没有任何关系一个
和 B
因此,它们之间没有关系,包括没有排序关系,换句话说,你甚至不能假设一个将在另一个之后运行,即
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, i.e.
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
当然,有没有担保。
要强制实现两个消费者之间的依赖关系,你必须适当地将它们链接起来,例如
To enforce your dependency between the two consumers, you have to chain them appropriately, e.g.
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();
这里,第二个消费者链接到 base
和 next
,从 base
接收结果,但依赖于 next
完成(如果没有结果通常你通常不会要求 - 如果你有这样的情况,也许你想重新考虑你的设计。)
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).
或者,您可以将第一个消费者
转换为函数
,它会传递该值,因此您可以通过 thenApply
链接它,以允许链接另一个 thenAccept
阶段。
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.
这篇关于执行CompletableFuture的多个thenAccept块的顺序是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!