[英]Behaviour of ForkJoinPool in CompletableFuture.supplyAsync()
我正在比较两种情况下的CompletableFuture.supplyAsync()的行为,在这两种情况下,我设置了自定义ExecutorService或希望我的Supplier由默认执行器(如果未指定)执行,该默认执行器为ForkJoinPool.commonPool()
让我们看一下区别:
public class MainApplication {
public static void main(final String[] args) throws ExecutionException, InterruptedException {
Supplier<String> action1 = () -> {
try {
Thread.sleep(3000);
}finally {
return "Done";
}
};
Function<String, String> action2 = (input) -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
return input + "!!";
}
};
final ExecutorService executorService = Executors.newFixedThreadPool(4);
CompletableFuture.supplyAsync(action1, executorService)
.thenApply (action2)
.thenAccept (res -> System.out.println(res));
System.out.println("This is the end of the execution");
}
}
在这种情况下,我将executorService传递给我的supplyAsync(),并显示:
这是执行的结束
完成!
因此,在主执行结束后将打印“完成”。
但是如果我改用:
CompletableFuture.supplyAsync(action1)
因此,我不会传递自定义的executorService,而CompletableFuture类在ForkJoinPool.commonPool()的幕后使用,然后根本不会打印“ Done”:
这是执行的结束
流程结束,退出代码为0
为什么?
ForkJoinPool
使用的后台驻留程序线程不会阻止JVM退出。 另一方面,由Executors创建的ExecutorService中的线程是非守护程序线程,因此,在您显式关闭线程池之前,它可以防止JVM退出。
还要注意,在您的示例中,您需要在最后关闭池以终止JVM。
executorService.shutdown();
因此,一种解决方案是让主线程等待几秒钟,直到像这样完成计算,
Thread.sleep(4000);
在两种情况下,当您这样做
CompletableFuture.supplyAsync(action1, executorService)
.thenApply (action2)
.thenAccept (res -> System.out.println(res));
您无需等待任务完成。 但是随后您的程序将退出,并且普通的fork join池的方式有所不同:
ForkJoinPool.commonPool()
和常规的执行人服务:
final ExecutorService executorService = Executors.newFixedThreadPool(4);
..在尝试调用System.exit(...)等效项时进行反应。
这是doc关于fork fork公共池的内容,您应该注意以下几点:
但是,此池和任何正在进行的处理都会在程序System.exit(int)上自动终止 。 任何依赖异步任务处理在程序终止之前完成的程序都应在退出之前调用commonPool()。awaitQuiescence。
这是指向ExecutorService docs的链接,您可能需要注意:
shutdown()方法将允许先前提交的任务在终止之前执行
我认为这可能与您要求的有所不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.