我不明白CompletableFuture / supplyAsync在这里发生了什么。

如果我从先前实例化的CompletableFuture对象中调用supplyAsync方法,它将永远不会完成:

public static void ex1() throws ExecutionException, InterruptedException {
   final CompletableFuture<String> cf = new CompletableFuture<>();
   cf.supplyAsync(() -> {
      System.out.println("Main.m3");
      return "Main";
   });
   System.out.println("Start: cf = " + cf);
   final String value = cf.get();
   System.out.println("End: value = " + value);
}


这是输出:

Start: cf = java.util.concurrent.CompletableFuture@5b480cf9[Not completed]
Main.m3


如您所见,System.out.println("End: cf = " + cf);从未执行。

为了使其运行,我需要在supplyAsync主体中放置一个complete(my value)

但是,如果我在创建CompletableFuture时直接调用supplyAsync(或通过调用静态CompletableFuture.supplyAsync):

public static void ex2() throws ExecutionException, InterruptedException {
   final CompletableFuture<String> cf = new CompletableFuture<>()
      .supplyAsync(() -> {
         System.out.println("Main.m3");
         return "Main";
      });
   System.out.println("Start: cf = " + cf);
   final String value = cf.get();
   System.out.println("End: value = " + value);
}


它按预期工作。您可以在此处看到输出:

Start: cf = java.util.concurrent.CompletableFuture@5b480cf9[Not completed]
Main.m3
End: value = Main


所以我的问题是:为什么这样?我有什么想念的吗?

最佳答案

supplyAsync是返回新staticCompletableFuture方法,不应通过实例调用它。

在第一种情况下,您正在从未启动任何内容的get()上调用CompletableFuture

实际上,您会注意到,调用ex1()时,程序将永远保持pending状态。因此,它永远无法执行下一行,该行将打印(并行计算的其他Main的)结果Future

关键是您不要在任何地方存储第二个CompletableFuture。因此,您将无法调用正确的get()



在第二种情况下,您将使用返回值supplyAsync构建实例,并将其存储在cf中。这是构造CompletableFuture的正确方法。 (new CompletableFuture<>()部分是多余的;实际上,您可以通过supplyAsync立即为其分配一个新实例)。

因此,当您调用get()时,您将等待正确的CompletableFuture返回其结果。

关于java - CompletableFuture.supplyAsync与新的CompletableFuture(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48906538/

10-12 06:38