[英]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.