"重用"CompletableFuture是安全/良好的做法

use*_*547 5 java java-8 completable-future

在试验时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));
Run Code Online (Sandbox Code Playgroud)

它有效,印刷

bar 42
baz 42
finished processing of 42
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 6

你所描述的不是a的"重用" CompleteableFuture,因为它仍然只执行一个动作并且最多完成一次.

您只是注册多个依赖阶段,这完全在预见的用途范围内.在任何一点上,文献都没有提出依赖阶段必须形成一个单一的线性链.用例已经由界面CompletionStage<T>描述:

可能异步计算的一个阶段,在另一个CompletionStage完成时执行操作或计算值.阶段在其计算终止时完成,但这又可以触发其他依赖阶段.

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

毕竟,当你有两个动作a和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"等日志.

  • 它是关于一个方法返回一个`CompletableFuture`的场景,它可以在每次调用时返回相同的已完成的未来,如果它与其语义相匹配的话.如果有人在返回的未来使用了一个`obtrude ...`方法,那么这个方法会破坏,但我不会称之为真正的问题.如果项目中涉及的开发人员想要破解应用程序,那么总会有一种方法(对于具有访问覆盖的反射问好...).`obtrude ...`方法显然不在正常使用情况之外.那里提到的另一个问题只适用于从未完成的期货. (2认同)