---
title: 誤解しがちなThreadPoolTaskExecutorの設定
tags: ["Java", "Spring"]
categories: ["Programming", "Java", "org", "springframework", "scheduling", "concurrent"]
date: 2018-01-10T02:35:56Z
updated: 2023-06-08T05:28:32Z
---

Springの[`TaskScheduler`](https://docs.spring.io/autorepo/docs/spring-framework/5.0.x/spring-framework-reference/integration.html#scheduling)のうち、もっともよく使われる`org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor`の設定ミスが多いです。


* `corePoolSize`
* `maxPoolSize`
* `queueCapacity`

が設定項目としてあります。

これだけ見ると、この`Executor`が`Thead`を作る順としては

1. `corePoolSize`を`Thread`を最初に作る
2. `corePoolSize`が一杯になると`maxPoolSize`まで`Thread`を増やす
3. `maxPoolSize`を越えると、`queueCapacity`までキューイングする
4. `queueCapacity`を越えるとrejectされる

と思いがちです。

しかし、これは誤解です。

正しくは


1. `corePoolSize`まで`Thread`を作る
2. `corePoolSize`が一杯になると`queueCapacity`までキューイングする
3. `queueCapacity`を越えると`maxPoolSize`まで`Thread`を増やす
4. `maxPoolSize`を越えるとrejectされる

です。

`corePoolSize`のデフォルト値は`1`、`maxPoolSize`,`queueCapacity`共にデフォルト値は`Integer.MAX_VALUE`です。


次のような設定は意味がありません。


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

`queueCapacity`を設定していないので、最大スレッド数は`4`です。それ以上のリクエストは全てキューイングされます。`40`という数字に意味がありません。

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

`corePoolSize`も`queueCapacity`を設定していないので、最大スレッド数は`1`です。それ以上のリクエストは全てキューイングされます。


スレッド数を`4`-`40`に設定したいのであれば、例えば次のように設定する必要があります。（ただし、初回に4スレッドできる訳ではありません）

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

設定値を次の順番で認識しておいたほうが間違いにくいです。

* `corePoolSize`
* `queueCapacity`
* `maxPoolSize`

あるいは最大スレッド数が`40`でることのみ指定したい場合は

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

でOKです。




ちなみに`ThreadPoolTaskExecutor`が委譲している`java.util.concurrent.ThreadPoolExecutor`を作るときは次のような使い方をすることが多いと思います。


``` java
ExecutorService executorService = Executors.newFixedThreadPool(40);
```

これは

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

に近いです。


Spring Bootを使う場合は、上記のように`ThreadPoolTaskExecutor`を定義するよりもAutoConfigurationを使用すべきです。

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

この場合は、次のプロパティを使ってPool sizeを設定できます。

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

---

直感的に`Thread`を増やすことを先に行なって欲しい場合は以下のriptide-concurrentの使用を検討してみてください。<br>
https://github.com/zalando/riptide/tree/main/riptide-concurrent
