[英]Behaviour of ForkJoinPool in CompletableFuture.supplyAsync()
I'm comparing the behaviour of CompletableFuture.supplyAsync() in the two cases in which I set a custom ExecutorService or I want my Supplier to be executed by the default executor (if not specified) which is ForkJoinPool.commonPool() 我正在比较两种情况下的CompletableFuture.supplyAsync()的行为,在这两种情况下,我设置了自定义ExecutorService或希望我的Supplier由默认执行器(如果未指定)执行,该默认执行器为ForkJoinPool.commonPool()
Let's see the difference: 让我们看一下区别:
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");
}
}
In this case I'm passing executorService to my supplyAsync() and it prints: 在这种情况下,我将executorService传递给我的supplyAsync(),并显示:
This is the end of the execution 这是执行的结束
Done!! 完成!
So "Done" gets printed after the end of the main execution. 因此,在主执行结束后将打印“完成”。
BUT if I use instead: 但是如果我改用:
CompletableFuture.supplyAsync(action1)
so I don't pass my custom executorService and the CompletableFuture class uses under the hood the ForkJoinPool.commonPool() then "Done" is not printed at all: 因此,我不会传递自定义的executorService,而CompletableFuture类在ForkJoinPool.commonPool()的幕后使用,然后根本不会打印“ Done”:
This is the end of the execution 这是执行的结束
Process finished with exit code 0 流程结束,退出代码为0
Why? 为什么?
ForkJoinPool
uses daemon threads that does not prevent JVM from exiting. ForkJoinPool
使用的后台驻留程序线程不会阻止JVM退出。 On the other hand the threads in the ExecutorService created by Executors are non-daemon threads, hence it keeps JVM from exiting until you explicitly shutdown the thread pool. 另一方面,由Executors创建的ExecutorService中的线程是非守护程序线程,因此,在您显式关闭线程池之前,它可以防止JVM退出。
Also notice that in your example you need to shutdown the pool at the end in order to terminate the JVM. 还要注意,在您的示例中,您需要在最后关闭池以终止JVM。
executorService.shutdown();
So, one solution would be to keep the main thread waiting for few seconds until your computation is completed like so, 因此,一种解决方案是让主线程等待几秒钟,直到像这样完成计算,
Thread.sleep(4000);
In both cases when you do 在两种情况下,当您这样做
CompletableFuture.supplyAsync(action1, executorService)
.thenApply (action2)
.thenAccept (res -> System.out.println(res));
you don't wait for task completition. 您无需等待任务完成。 But then you program is going to exit and there is differences how common fork join pool: 但是随后您的程序将退出,并且普通的fork join池的方式有所不同:
ForkJoinPool.commonPool()
and regular executor service: 和常规的执行人服务:
final ExecutorService executorService = Executors.newFixedThreadPool(4);
..react on attempt to call System.exit(...) equivalent. ..在尝试调用System.exit(...)等效项时进行反应。
This is what doc says about fork join common pool, you should point attention to that: 这是doc关于fork fork公共池的内容,您应该注意以下几点:
However this pool and any ongoing processing are automatically terminated upon program System.exit(int) . 但是,此池和任何正在进行的处理都会在程序System.exit(int)上自动终止 。 Any program that relies on asynchronous task processing to complete before program termination should invoke commonPool().awaitQuiescence, before exit. 任何依赖异步任务处理在程序终止之前完成的程序都应在退出之前调用commonPool()。awaitQuiescence。
That is link to ExecutorService docs , you may point attention to: 这是指向ExecutorService docs的链接,您可能需要注意:
The shutdown() method will allow previously submitted tasks to execute before terminating shutdown()方法将允许先前提交的任务在终止之前执行
I think that may be a difference you asking about. 我认为这可能与您要求的有所不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.