Jan 10, 2018
Jun 8, 2023
N/A Views
MD
warning
This article was last updated more than 2 years ago. The information may be outdated.

Warning

This article was automatically translated by OpenAI (gpt-4o).It may be edited eventually, but please be aware that it may contain incorrect information at this time.

There are many common mistakes in configuring org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor, which is one of the most frequently used components of Spring's TaskScheduler.

  • corePoolSize
  • maxPoolSize
  • queueCapacity

These are the configuration items.

At first glance, it might seem that this Executor creates Threads in the following order:

  1. Create Threads up to corePoolSize first
  2. When corePoolSize is full, increase Threads up to maxPoolSize
  3. When maxPoolSize is exceeded, queue up to queueCapacity
  4. When queueCapacity is exceeded, reject the request

However, this is a misunderstanding.

The correct order is:

  1. Create Threads up to corePoolSize
  2. When corePoolSize is full, queue up to queueCapacity
  3. When queueCapacity is exceeded, increase Threads up to maxPoolSize
  4. When maxPoolSize is exceeded, reject the request

The default value for corePoolSize is 1, and the default values for both maxPoolSize and queueCapacity are Integer.MAX_VALUE.

The following configuration is meaningless:

@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(4);
    taskExecutor.setMaxPoolSize(40);
    return taskExecutor;
}

Since queueCapacity is not set, the maximum number of threads is 4. All requests beyond that will be queued. The number 40 is meaningless.

@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setMaxPoolSize(40);
    return taskExecutor;
}

Since neither corePoolSize nor queueCapacity is set, the maximum number of threads is 1. All requests beyond that will be queued.

If you want to set the number of threads to 4-40, you need to configure it as follows (note that it does not create 4 threads initially):

@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(4);
    taskExecutor.setQueueCapacity(4);
    taskExecutor.setMaxPoolSize(40);
    return taskExecutor;
}

It is less confusing to recognize the configuration values in the following order:

  • corePoolSize
  • queueCapacity
  • maxPoolSize

Alternatively, if you only want to specify that the maximum number of threads is 40, you can do so as follows:

@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(40);
    return taskExecutor;
}

By the way, when creating the java.util.concurrent.ThreadPoolExecutor that ThreadPoolTaskExecutor delegates to, it is often used as follows:

ExecutorService executorService = Executors.newFixedThreadPool(40);

This is similar to:

@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(40);
    taskExecutor.setMaxPoolSize(40);
    return taskExecutor;
}

When using Spring Boot, it is better to use AutoConfiguration rather than defining ThreadPoolTaskExecutor as above.

https://docs.spring.io/spring-boot/reference/features/task-execution-and-scheduling.html#page-title

In this case, you can set the pool size using the following properties:

spring.task.execution.pool.core-size=4
spring.task.execution.pool.queue-capacity=4
spring.task.execution.pool.max-size=40

If you intuitively want to increase Threads first, consider using riptide-concurrent as follows:

https://github.com/zalando/riptide/tree/main/riptide-concurrent

Found a mistake? Update the entry.
Share this article: