ForkJoinPool在CompletableFuture.supplyAsync()中的行为

时间:2019-01-04 08:01:33

标签: java multithreading threadpool completable-future forkjoinpool

在两种情况下,我比较 CompletableFuture.supplyAsync() 的行为,在这种情况下,我设置了自定义ExecutorService或希望由默认执行程序(如果未指定)为 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()的幕后使用,则根本不打印“完成”:

  

这是执行的结束

     

以退出代码0结束的过程

为什么?

2 个答案:

答案 0 :(得分:1)

ForkJoinPool使用的守护进程线程不会阻止JVM退出。另一方面,由Executors创建的ExecutorService中的线程是非守护程序线程,因此,在您显式关闭线程池之前,它可以防止JVM退出。

还要注意,在您的示例中,您需要在最后关闭池以终止JVM。

executorService.shutdown();

因此,一种解决方案是让主线程等待几秒钟,直到像这样完成计算为止,

Thread.sleep(4000);

答案 1 :(得分:1)

两种情况下

CompletableFuture.supplyAsync(action1, executorService)
                     .thenApply  (action2)
                     .thenAccept (res -> System.out.println(res));

您不必等待任务完成。但是然后您的程序将退出,并且普通的fork连接池的方式有所不同:

ForkJoinPool.commonPool()

和常规执行服务:

final ExecutorService executorService = Executors.newFixedThreadPool(4);

..在尝试调用等效于System.exit(...)时反应。

这是关于{fork join common pool的doc says的内容,您应该引起注意:

  

但是此池和任何正在进行的处理会自动进行   在程序System.exit(int)上终止。任何依赖的程序   异步任务处理在程序终止之前完成   退出前应调用commonPool()。awaitQuiescence。

这是ExecutorService docs的链接,您可能需要注意:

  

shutdown()方法将允许先前提交的任务执行   终止之前

我认为这可能与您要求的有所不同。