我无法发现这两种方法的行为为何不同。两者之间的唯一区别是sleep方法调用。
在第一种方法中,我期望第二个将来的执行将等待第一个将来完成,因为它取决于第一个的结果。
请帮助我理解为什么两种方法的行为都不同,或者我的代码在逻辑上有什么错误吗?
我尝试在调试模式下运行,但仍然给出了相同的结果。
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);
}
第一种方法的预期输出:“您好,然后调用了compose。”
第一种方法的实际输出:空字符串
第二种方法的预期和实际输出相同。
输出:“您好,然后调用了compose”
答案 0 :(得分:3)
这里的问题是
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<
哪个说明了不仅“睡眠”任务而且许多“睡眠”任务都没有终止。
如果要等待所有CompletableFuture任务终止,可以使用
CompletableFuture.join()
在主线程上。