java - 创建大型固定线程池的后果

标签 java multithreading concurrency threadpool

我正在开发一个标准的服务器应用程序。每个请求的处理被分解成几个阶段(第二阶段要求第一个阶段完成,等等)。现在,这些阶段中的一个需要相当长的时间,但它本身可以分解成几十个任务,这些任务彼此不依赖,因此是可并行的。我想向 SlowStageService 添加一个线程池,并且想知道如何最好地调整它的大小。大多数时候线程池最好至少有一个空缺,这意味着它必须以与服务器接收请求一样快或更快的速度处理任务;这产生了线程池大小的合理下限。但是,我想在尺寸上大方一些,因为计算中涉及的许多数字可能会发生变化。

所以我的问题是:使我的池太大(比如 3 或 4 倍)并且有很多空闲线程的缺点是什么?我知道它浪费了一些资源,但它实际上并没有保留任何 CPU 并因此使其无法用于其他请求,对吗?通常可以在实践中有多少懈怠?假设我计算出 6 个线程是我需要的最小值;在中等负载下在 24 核盒子上说 12 是否安全?

在我写这篇文章时,听起来我可能需要的是一个范围相当窄(3 或 4 倍)的 ThreadPoolExecutor

最佳答案

您应该引用 Brian Goetz 所著的《Java 并发实践》一书中的第 8.2 节。

如果您的阶段是计算密集型阶段并且 I/O 非常少,那么线程池的最佳大小 = CPU 核心数 + 1(因此在您的情况下为 25)。 但是,如果您的阶段中存在 I/O 绑定(bind)任务,那么实现最佳响应时间的线程池的最佳适用大小取决于多种因素:

  1. CPU 数量 - N
  2. CPU 的目标利用率 - UC
  3. I/O 操作的等待时间(阻塞状态)(W) 与计算时间 (C) 的比率。

NUM_THREADS = N * UC * (1+(W/C))

除了上述指标外,影响池大小计算的其他因素还有内存要求、连接池大小、文件句柄和套接字句柄。

鉴于上述调整线程池大小的理论;我的经验表明,获得最佳池大小的最佳方法是分析各种工作负载下的应用程序,并针对轻型、中型和重型工作负载大小得出池大小。

此外,永远不要对最大线程池大小进行硬编码 - 它应该始终是一个可配置参数,以便可以根据遇到的工作负载在现场进行调整。

关于java - 创建大型固定线程池的后果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34824142/

相关文章:

java - 如何将菜单项添加到现有的 Android 应用程序菜单?

Java HEAD/GET 请求与 Linux 请求

c# - 将控制台聊天程序转换为 GUI

c# - XElement 的添加操作是线程安全的吗?

java - 我在哪里可以找到 JMock Blitzer?

两个耦合类中的 Java EE EJB 注入(inject)

java - 为一个系列中的特定节点设置样式 - JavaFX

c# - 在计时器中使用QueueUserWorkItem时发生ThreadStateException

java类连续2-3分钟后调用rest api

java - Java中对 volatile 对象进行非 volatile 引用的行为