Java 更改工作线程数量

Java change worker threads amount

我正在使用 ExecutorService 创建一个固定的线程池并启动几个工作线程,这些工作线程侦听发生的事情然后执行它们的工作。 但是有时我想增加或减少同时 运行 的线程数量,以便微调应用程序的性能(无需重新启动应用程序或杀死任何当前 运行 线程) . 我应该创建自己的线程池,还是有办法拥有一个大小不断变化的池,以根据需要处理 start/stop 工作人员。

ThreadPoolExecutor lets you do that. See setCorePoolSize and setMaximumPoolSize

ThreadPoolExecutor 动态增减线程数。确保正确设置池大小。 CorePoolSize 定义生成的最大线程数。当定义的 BlockingQueue 大小有限时,MaxPoolSize 开始发挥作用。当您的队列大小有限时,会为每个提交的新任务生成新线程,直到达到核心池大小。如果队列中的请求数量增加超过队列的有限大小,则会生成新线程,直到它们达到 MaxPoolSize。

However sometimes I would like to increase or decrease the amount of threads that are running at the same time in order to fine tune the perfomance of the app (without restarting the app or killing any currently running threads).

如果你的意思是使用某种工具或其他东西动态改变那么我不确定,但你可以用一些代码逻辑来控制。

您可以使用 java.util.concurrent.ThreadPoolExecutor 并使用 CorePoolSizeMaxPoolSize 属性控制线程池

corePoolSize 和 maximumPoolSize:

  • ThreadPoolExecutor 将根据 corePoolSize(参见 getCorePoolSize())和 maximumPoolSize(参见 getMaximumPoolSize())设置的边界自动调整池大小(参见 getPoolSize())。
  • 当在方法 execute(java.lang.Runnable) 中提交新任务时,少于 corePoolSize 线程 运行,将创建一个新线程来处理请求,即使其他工作线程正在虚度。
  • 如果线程数大于 corePoolSize 但小于 maximumPoolSize 运行,只有在队列已满时才会创建新线程。

然而,在您做出决定之前,我建议您阅读以下摘自 ThreadPoolExecutor 的 Java 文档的摘录。

However, programmers are urged to use the more convenient Executors factory methods Executors.newCachedThreadPool() (unbounded thread pool, with automatic thread reclamation), Executors.newFixedThreadPool(int) (fixed size thread pool) and Executors.newSingleThreadExecutor() (single background thread), that preconfigure settings for the most common usage scenarios.


代码示例:
请参考下面的代码示例。您可以通过阅读代码和阅读 Java 文档来理解大部分内容。但是,可能不明显的是

  • 我们已使用 ArrayBlockingQueue 获得 20 容量的有界队列(您可以根据您的要求决定队列容量)。 因此,一旦队列中有超过 20 个任务在等待,新线程将被创建,但最大为 maxPoolSize
  • 根据负载,我们正在增加核心池线程的数量,这意味着将有更多线程处理您的任务,因此任务排队的机会更少。但是您也可以使用 maxPoolSize。

您可以阅读 ThreadPoolExecutor 的 "Queuing" 部分并根据您的要求决定其他队列。

ThreadPoolExecutor.setCorePoolSize(int)
设置核心线程数。这会覆盖构造函数中设置的任何值。如果新值小于当前值,多余的现有线程将在下一次空闲时终止。如果更大,新线程将在需要时启动以执行任何排队的任务

    //Read Java docs for details about construcutor...
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20));
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //Do your task...
        }
    };

    executeTasks(poolExecutor, runnable, false, false); //Compute last 2 parameters as you need and pass on required values.

public static void executeTasks(ThreadPoolExecutor poolExecutor, Runnable runnable, boolean isUnderLoad, boolean isOverLoad){
    if(isOverLoad && isUnderLoad){
        //Handle this situation, this should not be allowed, probably a coding bug can result this...
    }
    poolExecutor.submit(runnable);
    if(isUnderLoad){
        poolExecutor.setCorePoolSize(5);
    }
    if(isOverLoad){
        poolExecutor.setCorePoolSize(20);
    }
}