我不明白CompletableFuture/supplyAsync在这里发生了什么。
如果我从以前实例化的supplyAsync对象调用CompletableFuture方法,它永远不会完成:
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所以我的问题是:为什么?我遗漏了什么吗?
发布于 2018-02-21 13:19:51
supplyAsync是一个返回新CompletableFuture的static方法,不应该通过实例调用它。
在first case中,您在一个从未启动的CompletableFuture上调用get()。
实际上,您会注意到,当调用ex1()时,您的程序将永远处于pending状态。因此,它永远无法执行下一行,它打印结果Main (并行计算的其他Future的结果)。
重点是,您不将第二个CompletableFuture存储在任何地方。因此,您不可能调用正确的 get()。
在第二个案例中,您正在使用supplyAsync的返回值构建实例,并将其存储在cf中。这是构造CompletableFuture的正确方法。( new CompletableFuture<>()部分是多余的;实际上,您可以立即用supplyAsync为它分配一个新实例)。
因此,当您调用get()时,您将等待正确的CompletableFuture返回其结果。
发布于 2018-02-21 13:19:09
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提供的代码都是正确的。
https://stackoverflow.com/questions/48906538
复制相似问题