Java CompletableFutures:不加入/获取是否可以接受?

时间:2019-07-06 14:13:53

标签: java completable-future

不返回或加入CompletableFuture是否正确?

也就是说,此代码是否正确?

void noJoin() {
   CompletableFuture<Void> cfa = CompletableFuture
                                   .supplyAsync(() -> "a")
                                   .thenAccept(this::someSideEffect);

   CompletableFuture<Void> cfb = CompletableFuture
                                   .supplyAsync(() -> "b")
                                   .thenAccept(this::someSideEffect);
}

在上面的代码中,我们永远不知道期货是否成功完成,或者根本不完成。 (而且我什至不知道在noJoin中创建的Futures不符合垃圾回收的条件;但是大概ForkJoinPool.commonPool()可以保留这些引用吗?)

无论如何,如果这些期货是否成功与我们的计划真正无关紧要,那么noJoin的更好实现只是一个禁忌:

void noJoin() {}

如果这确实很重要,那么我们需要通过组合期货(与thenCompose串联,或与thenCombine或allOf并联)来加入或返回两者期货加入撰写的Future或将其返回给我们的呼叫者。

通过加入,如果Future中的任何一个例外,我们将阻止并抛出异常;或更妙的是,通过返回Future,我们保持异步,同时确保调用者获得拥有任何特殊结果的Future:

Future<Void> returnBothAsync() {

       CompletableFuture<Void> cfa = CompletableFuture
                                       .supplyAsync(() -> "a")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture<Void> cfb = CompletableFuture
                                       .supplyAsync(() -> "b")
                                       .thenAccept(this::someSideEffect);

       return CompletableFuture.allOf(cfa, cfb);
}

void joinBothBlocking() {

       CompletableFuture<Void> cfa = CompletableFuture
                                       .supplyAsync(() -> "a")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture<Void> cfb = CompletableFuture
                                       .supplyAsync(() -> "b")
                                       .thenAccept(this::someSideEffect);

       CompletableFuture.allOf(cfa, cfb).get(50L, TimeUnit.MILLISECONDS);
}

即使我们安排处理所有例外情况,我也认为这是正确的:

void noJoin() {
   CompletableFuture<Void> cfa = CompletableFuture
                                   .supplyAsync(() -> "a")
                                   .thenAccept(this::someSideEffect)
                                   .exceptionally(e -> {
                                         Logger.log(e);
                                         return DEFAULT;
                                   });

   CompletableFuture<Void> cfb = CompletableFuture
                                   .supplyAsync(() -> "b")
                                   .thenAccept(this::someSideEffect);
}

因为即使处理了例外情况/“不可能发生”,我们仍然不知道未来是否已经完成。

还是我错了?在某些情况下,noJoin中的代码是正确的吗?

1 个答案:

答案 0 :(得分:0)

这不是您问题的完整答案。可能要取决于确切的用例才能确定如何处理public static void createArmy(int units, int knights, int generals, int doctors){ Unit unit = new Unit[units]; Knight knight = new Knights[knights]; General general = new Generals[generals]; Doctor doctor = new Doctors[doctors]; for(int x = 0; x < units;x++){ unit[x] = new Unit("U"+(x+1)); } for(int x = 0; x < knights;x++){ knight[x] = new Knight("K"+(x+1)); } for(int x = 0; x < generals;x++){ general[x] = new General("G"+(x+1)); } for(int x = 0; x < doctors;x++){ doctor[x] = new Doctor("D"+(x+1)); } } 及其结果。

如果选择不等待CompletableFuture的结果,则可能必须确保使用的执行程序完成了所有任务。在您的情况下,使用的执行者是ForkJoinPool.commonPool(),其文档显示为:

  

[...]但是,此池和任何正在进行的处理都会在程序System.exit(int)上自动终止。任何依赖异步任务处理在程序终止之前完成的程序都应在退出之前调用commonPool()。awaitQuiescence。