繁体   English   中英

CompletableFuture.supplyAsync与新的CompletableFuture()

[英]CompletableFuture.supplyAsync vs new CompletableFuture()

我不明白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); 永远不会执行。

为了使其运行,我需要将一个complete(my value)放在supplyAsync的主体内。

但是,如果我在创建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是一个static方法,它返回一个新的CompletableFuture ,不应通过实例调用它。

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

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

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


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

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

java.util.concurrent.CompletableFuture#supplyAsync(java.util.function.Supplier<U>)是一个静态函数,因此在ex1中,您分配了CompletableFuture但从未使用过。

从Java 8来源:

/**
 * Returns a new CompletableFuture that is asynchronously completed
 * by a task running in the {@link ForkJoinPool#commonPool()} with
 * the value obtained by calling the given Supplier.
 *
 * @param supplier a function returning the value to be used
 * to complete the returned CompletableFuture
 * @param <U> the function's return type
 * @return the new CompletableFuture
 */
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
    return asyncSupplyStage(ASYNC_POOL, supplier);
}

在您的情况下,ex1应该是:

public static void ex1() throws ExecutionException, InterruptedException {
    CompletableFuture<String> cf = 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);
}

而ex2是正确的格式,但是您偶然通过分配新的CompletableFuture并调用静态方法而到达那里,但是在ex2中,您不会丢弃返回的值,而在ex1中,您却这样做。

在您的ex1和ex2中,您实际上是在调用相同的方法,上面为ex1提供的代码对于使用类名正确调用static而不丢弃返回的对象的两种情况都是正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM