📝 BLOG.IK.AM

@making's memo
(🗃 Categories 🏷 Tags)

誤解しがちなThreadPoolTaskExecutorの設定

🗃 {Programming/Java/org/springframework/scheduling/concurrent}

🏷 Java 🏷 Spring

🗓 Updated at 2018-01-10T02:44:40+09:00 by Toshiaki Maki  🗓 Created at 2018-01-10T02:35:56+09:00 by Toshiaki Maki  {✒️️ Edit  ⏰ History}


SpringのTaskSchedulerのうち、もっともよく使われるorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutorの設定ミスが多いです。

  • corePoolSize
  • maxPoolSize
  • queueCapacity

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

これだけ見ると、このExecutorTheadを作る順としては

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

と思いがちです。

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

正しくは

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

です。

corePoolSizeのデフォルト値は1maxPoolSize,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;
}

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

スレッド数を4-40に設定したいのであれば、例えば次のように設定する必要があります。

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

あるいはスレッド数40に固定したい場合は

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

でOKです。

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

  • corePoolSize
  • queueCapacity
  • maxPoolSize

ちなみに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;
}

に近いです。