在尝试CompletableFuture
时,我想知道给定的代码是否安全。
CompletableFuture<Integer> foo = CompletableFuture.supplyAsync(() -> 42);
foo.thenApply((bar) -> {
System.out.println("bar " + bar);
return bar;
})
.acceptEither(foo.thenApply((baz) -> {
System.out.println("baz " + baz);
return baz;
}),
(z) -> System.out.println("finished processing of " + z));
它有效,打印
bar 42
baz 42
finished processing of 42
在thenApply
的给定实例上多次调用CompletableFuture
或其他方法是否安全/好主意?
答案 0 :(得分:6)
您所描述的不是CompleteableFuture
的“重复使用”,因为它仍然只执行一次操作并且最多只能完成一次。
您只是注册多个依赖阶段,这完全在预见的用途范围内。在任何一点上,文献都没有提出依赖阶段必须形成一个单一的线性链。用例已由interface CompletionStage<T>
:
可能异步计算的一个阶段,它在另一个CompletionStage完成时执行操作或计算值。阶段在计算终止时完成,但这可能反过来触发其他依赖阶段。
请注意使用“其他依赖阶段”而不是“另一个依赖阶段”。在涉及阶段时,整个文档始终使用复数。这也适用于CompletableFuture<T>
实现类的文档。
毕竟,如果你有两个动作一个和 b ,它们彼此之间没有依赖关系但只依赖于 c ,那么有意义的是将两者都链接到 c ,而不是创建像 c → a → b 这样的链或 c → b → a ,因为后者会阻止独立操作 a 和 b ,这是并发API的全部要点。
请注意,以这种方式对依赖项进行建模时,不会保证您显示的结果。两个打印操作“bar”和“baz”彼此之间没有依赖关系,但仅限于42
值的供应商,并且计划打印“已完成处理”的操作为了完成 ,不是。因此,除了“bar”和“baz”输出的不确定顺序之外,您还可以看到“bar,finished processing,baz”或“baz,finished processing,bar”等日志。