SpringのTaskScheduler
のうち、もっともよく使われるorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
の設定ミスが多いです。
corePoolSize
maxPoolSize
queueCapacity
が設定項目としてあります。
これだけ見ると、このExecutor
がThead
を作る順としては
corePoolSize
をThread
を最初に作るcorePoolSize
が一杯になるとmaxPoolSize
までThread
を増やすmaxPoolSize
を越えると、queueCapacity
までキューイングするqueueCapacity
を越えるとrejectされる
と思いがちです。
しかし、これは誤解です。
正しくは
corePoolSize
までThread
を作るcorePoolSize
が一杯になるとqueueCapacity
までキューイングするqueueCapacity
を越えるとmaxPoolSize
までThread
を増やすmaxPoolSize
を越えるとrejectされる
です。
corePoolSize
のデフォルト値は1
、maxPoolSize
,queueCapacity
共にデフォルト値はInteger.MAX_VALUE
です。
次のような設定は意味がありません。
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(4);
taskExecutor.setMaxPoolSize(40);
return taskExecutor;
}
queueCapacity
を設定していないので、最大スレッド数は4
です。それ以上のリクエストは全てキューイングされます。40
という数字に意味がありません。
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(40);
return taskExecutor;
}
corePoolSize
もqueueCapacity
を設定していないので、最大スレッド数は1
です。それ以上のリクエストは全てキューイングされます。
スレッド数を4
-40
に設定したいのであれば、例えば次のように設定する必要があります。(ただし、初回に4スレッドできる訳ではありません)
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(4);
taskExecutor.setQueueCapacity(4);
taskExecutor.setMaxPoolSize(40);
return taskExecutor;
}
設定値を次の順番で認識しておいたほうが間違いにくいです。
corePoolSize
queueCapacity
maxPoolSize
あるいは最大スレッド数が40
でることのみ指定したい場合は
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(40);
return taskExecutor;
}
でOKです。
ちなみにThreadPoolTaskExecutor
が委譲しているjava.util.concurrent.ThreadPoolExecutor
を作るときは次のような使い方をすることが多いと思います。
ExecutorService executorService = Executors.newFixedThreadPool(40);
これは
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(40);
taskExecutor.setMaxPoolSize(40);
return taskExecutor;
}
に近いです。
直感的にThread
を増やすことを先に行なって欲しい場合は以下のriptide-concurrentの使用を検討してみてください。
https://github.com/zalando/riptide/tree/main/riptide-concurrent