【问题标题】:Thread of supplyAsync in java completable future uses different threads in different environmentsjava Completable Future中supplyAsync的线程在不同的环境中使用不同的线程
【发布时间】:2021-03-19 07:59:08
【问题描述】:

在我的 webapp 中,supplyAsync 方法在云 linux 环境中使用 forkjoin 池,但在本地 linux 机器中,相同的代码使用线程 1 线程 2 和类 web 应用程序类加载器。是否有任何配置可以更改可完成期货的默认线程池。我想获得云中的本地行为。使用 Web 应用程序类加载器进行线程化。 java版本java 11,tomcat版本8.5.24。

CompletableFuture<Void> asyncFuture = future.thenAcceptAsync(t -> {
        if (!complete.getAndSet(true)) {
            try {
                completeAction.accept(t);
            } finally {
                synchronized (executor) {
                    K.shutdown();
                }
            }
        }
    });
    synchronized (executor) {
        if (!executor.isShutdown()) {
            executor.schedule(() -> {
                if (!complete.getAndSet(true)) {
                    try {
                        asyncFuture.cancel(false);
                        timeoutAction.run();
                    } finally {
                        executor.shutdown();
                    }
                }
            }, 200, 50);
        }
    }

【问题讨论】:

标签: java tomcat classloader completable-future web-project


【解决方案1】:

CompletableFuture 是否为每个任务使用新线程或ForkJoinPool 取决于您系统的并行度:

所有没有显式 Executor 参数的异步方法都使用 ForkJoinPool.commonPool() 执行(除非它不支持至少两个并行级别,在这种情况下,会创建一个新线程来运行每个任务)。

(参见Javadoc)。

默认并行度级别比处理器数量少一,但您可以将其更改为设置系统属性java.util.concurrent.ForkJoinPool.common.parallelism 的任何值(参见ForkJoinPool)。

但是,我宁愿使用自定义的Executor,就像在 cmets 和你的 previous question 中一样。新创建的线程继承了当前线程上下文类加载器,而公共池没有,这一事实应该更多地被视为实现细节。您的代码应该在这两种情况下都能正常工作。

【讨论】:

  • 谢谢,我只是无法确定为什么相同的 java 和 tomcat 版本中的相同场景和相同代码的行为不同。唯一的区别是云环境中的操作系统。您已经提到“所有没有显式 Executor 参数的异步方法都是使用 ForkJoinPool.commonPool() 执行的”,但它在本地环境中是不同的。参见图 1。是的,我可以使用自定义执行器,但为什么会有这种差异?只想找出2个案例背后的原因
  • 您的本地计算机的 CPU 计数必须为 2 或更少。虽然现在这种配置对于物理硬件来说并不常见,但您可以use JVM options 来实现它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多