CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter into completableFuture()");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("start to out of completableFuture()");
return "a";
});
System.out.println("do something else");
cf1.thenApply(v -> v + " b").thenAcceptAsync(v ->
System.out.println(v)
);
System.out.println("finalize...");
//cannot get expected result, if this line was comment out.
//TimeUnit.SECONDS.sleep(10);
代码如上。
在jdk8中编写使用CompletableFuture的示例时,我感到很困惑。
我必须添加最后一行
TimeUnit.SECONDS.sleep(10);
获得预期结果。
如果我不让它的主线程进入休眠状态,我想知道程序是否已经结束。如果没有,为什么我不能得到输出?
非常感谢你的时间。
答案 0 :(得分:3)
当没有非守护程序线程正在运行时,JVM终止,因此如果异步操作仅由守护程序线程执行,它将在主线程终止时终止,而不是继续后台操作。
有几种方法可以解决这个问题。
如果后台计算形成单个依赖关系链,则可以使用最后一个操作来等待其完成,因为它的完成意味着所有先前阶段的完成。让主线程等到完成将JVM的终止推迟到该点:
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter into completableFuture()");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("start to out of completableFuture()");
return "a";
});
System.out.println("do something else");
CompletableFuture last
= cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
System.out.println("finalize...");
last.join();
考虑documentation of CompletableFuture
:
使用ForkJoinPool.commonPool()执行没有显式Executor参数的所有 async 方法(除非它不支持至少两个的并行级别,在这种情况下,创建一个新的Thread运行每个任务。)
由于该F / J公共池的属性是使用守护程序线程,因此在这种情况下,我们可以使用该知识等待所有待处理任务的完成,这与这些待处理任务之间的依赖关系无关:
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter into completableFuture()");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("start to out of completableFuture()");
return "a";
});
System.out.println("do something else");
cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
System.out.println("finalize...");
if(ForkJoinPool.getCommonPoolParallelism()>1)
ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);
使用显式执行程序,它不会使用守护程序线程。 JRE提供的线程池执行程序,让ForkJoinPool
放在一边,默认情况下使用非守护程序线程:
final ExecutorService threadPool = Executors.newCachedThreadPool();
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("enter into completableFuture()");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
System.out.println("start to out of completableFuture()");
return "a";
}, threadPool);
System.out.println("do something else");
cf1.thenApply(v -> v + " b").thenAcceptAsync(System.out::println);
System.out.println("finalize...");
threadPool.shutdown();
请注意threadPool.shutdown();
并不意味着等待,也不会停止待处理的任务;它只会停止接受新任务,并确保在处理完所有待处理任务后池池线程将终止。您可以在使用supplyAsync
后直接放置它,而不会改变行为。
因此,第三个解决方案是让main
线程退出的唯一解决方案,JVM将继续处理,直到处理完所有挂起的后台任务,因为它们在非守护程序线程中运行。
答案 1 :(得分:0)
您可以暂停CompletableFuture
,直到CompletableFuture#join完成,例如:
CompletableFuture<Void> stage = cf1.thenApply(v -> v + " b").thenAcceptAsync(v ->
System.out.println(v)
);
System.out.println("finalize...");
// v--- the main thread wait until the stage is completed
stage.join();