safe/good 练习 "reuse" CompletableFuture

is it safe/good practice to "reuse" CompletableFuture

在试验 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

CompletableFuture 的给定实例上多次调用 thenApply 或其他方法是 safe/a 好主意吗?

您所描述的不是 CompleteableFuture 的“重用”,因为它仍然只执行一个操作并且最多完成一次。

你只是注册了多个依赖阶段,完全在预见的使用范围之内。文档在任何时候都没有建议依赖阶段必须形成一个线性链。用例已由 interface CompletionStage<T>:

描述

A stage of a possibly asynchronous computation, that performs an action or computes a value when another CompletionStage completes. A stage completes upon termination of its computation, but this may in turn trigger other dependent stages.

注意使用“其他依赖阶段”而不是“另一个依赖阶段”。在涉及依赖阶段时,整个文档始终使用复数形式。这也适用于 CompletableFuture<T> 实现 class.

的文档

毕竟,当您有两个动作 ab 时,它们彼此没有依赖关系,但依赖于 c,唯一有意义的是将两者都链接到 c,而不是创建一个像 c 的链→ abcba 因为后者会抑制独立动作 ab 的并发执行,这就是重点并发性 API.

请注意,以这种方式对依赖项建模时,无法保证您所显示的结果。 “bar”和“baz”这两个打印操作彼此没有依赖关系,只依赖于 42 值的供应商,打印“finished processing 的操作”计划完成其中其中之一不是两者。因此,除了“bar”和“baz”输出的不确定顺序外,您还可以看到类似“bar, finished processing, baz”或“baz, finished processing, bar”的日志。