我无法找出为什么这两种方法的行为不同。两者之间的唯一区别是 sleep 方法调用。
在第一种方法中,我期望第二个 future 执行将等待第一个 future 完成,因为它取决于第一个 future 的结果。
请帮助我理解为什么这两种方法的行为不同,或者我的代码中有什么逻辑上的错误吗?
我尝试在 Debug模式下运行,但仍然给出相同的结果。
public static void thenComposeWithSleep() {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Hello";
}).thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
completableFuture.thenAccept(System.out::println);
}
public static void thenCompose() {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
completableFuture.thenAccept(System.out::println);
}
第一个方法的预期输出:“Hello,然后 compose 被调用”。
第一种方法的实际输出:空字符串
第二种方法的预期输出和实际输出相同。
输出:“Hello,然后 compose 被调用”
最佳答案
这里的问题是
CompletableFuture.supplyAsync()
将执行交给
ForkJoinPool.commonPool()
当它以守护进程模式运行时(根据 Java7 文档,这是默认的),如果主线程终止,所有未完成的异步任务将被丢弃并且永远不会完成。
所以我的猜测是你所假设的“空字符串”实际上是
System.out::println
根本没有执行。
为全类说明这一点
public class DaemonsAtPlay {
public static void thenComposeWithSleep() {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Slept"; //HERE
}).thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
completableFuture.thenAccept(DaemonsAtPlay::report); //HERE
}
public static void thenCompose() {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " Then compose is been called"));
completableFuture.thenAccept(DaemonsAtPlay::report); //HERE
}
private static final AtomicInteger counter = new AtomicInteger();
static void report(String msg) {
System.out.println("report: " + counter.incrementAndGet() + "; message: >" + msg + "<");
}
public static void executeMultiple(int iterations, boolean withsleep) {
for(int i=0; i<iterations; ++i) {
if(withsleep) {
thenComposeWithSleep();
} else {
thenCompose();
}
}
}
public static void main(String... none) throws Exception {
executeMultiple(100, false);
executeMultiple(100, true);
report("exiting main");
}
}
我得到了输出
report: 1; message: >Hello Then compose is been called<
report: 2; message: >Hello Then compose is been called<
report: 3; message: >Hello Then compose is been called<
report: 4; message: >Hello Then compose is been called<
report: 5; message: >Hello Then compose is been called<
report: 6; message: >Hello Then compose is been called<
report: 7; message: >Hello Then compose is been called<
report: 8; message: >Hello Then compose is been called<
report: 9; message: >Hello Then compose is been called<
report: 10; message: >Hello Then compose is been called<
report: 11; message: >Hello Then compose is been called<
report: 12; message: >Hello Then compose is been called<
report: 13; message: >Hello Then compose is been called<
report: 14; message: >Hello Then compose is been called<
report: 15; message: >Hello Then compose is been called<
report: 16; message: >Hello Then compose is been called<
report: 17; message: >Hello Then compose is been called<
report: 18; message: >Hello Then compose is been called<
report: 19; message: >Hello Then compose is been called<
report: 20; message: >Hello Then compose is been called<
report: 21; message: >Hello Then compose is been called<
report: 22; message: >exiting main<
这说明不仅“ sleep ”任务没有终止,许多“未 sleep ”任务也没有终止。
如果你想等待所有 CompletableFuture 任务终止,你可以使用
CompletableFuture.join()
在主线程上。
关于java - 这2种方法的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57500928/