ThreadPoolTaskExecutor corePoolSize et maxPoolSize

1. Vue d'ensemble

Spring ThreadPoolTaskExecutor est un JavaBean qui fournit une abstraction autour d'une instance java.util.concurrent.ThreadPoolExecutor et l'expose en tant que Spring org.springframework.core.task.TaskExecutor . De plus, il est hautement configurable grâce aux propriétés de corePoolSize, maxPoolSize, queueCapacity, allowCoreThreadTimeOut et keepAliveSeconds. Dans ce didacticiel, nous examinerons les propriétés corePoolSize et maxPoolSize .

2. corePoolSize et maxPoolSize

Les utilisateurs novices dans cette abstraction peuvent facilement être confus au sujet de la différence entre les deux propriétés de configuration. Par conséquent, regardons chacun indépendamment.

2.1. corePoolSize

Le corePoolSize est le nombre minimum de travailleurs à rester en vie sans dépassement de délai. C'est une propriété configurable de ThreadPoolTaskExecutor . Toutefois, l' abstraction ThreadPoolTaskExecutor délègue la définition de cette valeur au java.util.concurrent.ThreadPoolExecutor sous-jacent . Pour clarifier, tous les threads peuvent expirer - en définissant effectivement la valeur de corePoolSize à zéro si nous avons défini allowCoreThreadTimeOut sur true .

2.2. maxPoolSize

En revanche, maxPoolSize définit le nombre maximum de threads pouvant être créés . De même, la propriété maxPoolSize de ThreadPoolTaskExecutor délègue également sa valeur au java.util.concurrent.ThreadPoolExecutor sous-jacent . Pour clarifier, maxPoolSize dépend de queueCapacity dans la mesure où ThreadPoolTaskExecutor ne créera un nouveau thread que si le nombre d'éléments dans sa file d'attente dépasse queueCapacity .

3. Quelle est donc la différence?

La différence entre corePoolSize et maxPoolSize peut sembler évidente. Cependant, il y a quelques subtilités concernant leur comportement.

Lorsque nous soumettons une nouvelle tâche à ThreadPoolTaskExecutor, il crée un nouveau thread si moins de threads corePoolSize sont en cours d'exécution, même s'il y a des threads inactifs dans le pool, ou si moins de threads maxPoolSize sont en cours d'exécution et que la file d'attente définie par queueCapacity est pleine.

Ensuite, examinons du code pour voir des exemples de mise en action de chaque propriété.

4. Exemples

Tout d'abord, disons que nous avons une méthode qui exécute de nouveaux threads, à partir de ThreadPoolTaskExecutor , nommée startThreads :

public void startThreads(ThreadPoolTaskExecutor taskExecutor, CountDownLatch countDownLatch, int numThreads) { for (int i = 0; i  { try { Thread.sleep(100L * ThreadLocalRandom.current().nextLong(1, 10)); countDownLatch.countDown(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } }

Testons la configuration par défaut de ThreadPoolTaskExecutor , qui définit un corePoolSize d'un thread, un maxPoolSize illimité et un queueCapacity illimité . En conséquence, nous nous attendons à ce que quel que soit le nombre de tâches que nous démarrons, nous n'aurons qu'un seul thread en cours d'exécution:

@Test public void whenUsingDefaults_thenSingleThread() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.afterPropertiesSet(); CountDownLatch countDownLatch = new CountDownLatch(10); this.startThreads(taskExecutor, countDownLatch, 10); while (countDownLatch.getCount() > 0) { Assert.assertEquals(1, taskExecutor.getPoolSize()); } }

Maintenant, modifions corePoolSize à un maximum de cinq threads et assurons-nous qu'il se comporte comme annoncé. En conséquence, nous nous attendons à ce que cinq threads soient démarrés quel que soit le nombre de tâches soumises à ThreadPoolTaskExecutor :

@Test public void whenCorePoolSizeFive_thenFiveThreads() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.afterPropertiesSet(); CountDownLatch countDownLatch = new CountDownLatch(10); this.startThreads(taskExecutor, countDownLatch, 10); while (countDownLatch.getCount() > 0) { Assert.assertEquals(5, taskExecutor.getPoolSize()); } }

De même, nous pouvons incrémenter maxPoolSize à dix tout en laissant corePoolSize à cinq. En conséquence, nous prévoyons de démarrer seulement cinq threads. Pour clarifier, seuls cinq threads démarrent car queueCapacity est toujours illimitée:

@Test public void whenCorePoolSizeFiveAndMaxPoolSizeTen_thenFiveThreads() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(10); taskExecutor.afterPropertiesSet(); CountDownLatch countDownLatch = new CountDownLatch(10); this.startThreads(taskExecutor, countDownLatch, 10); while (countDownLatch.getCount() > 0) { Assert.assertEquals(5, taskExecutor.getPoolSize()); } }

De plus, nous allons maintenant répéter le test précédent mais incrémenter queueCapacity à dix et démarrer vingt threads. Par conséquent, nous prévoyons maintenant de démarrer dix threads au total:

@Test public void whenCorePoolSizeFiveAndMaxPoolSizeTenAndQueueCapacityTen_thenTenThreads() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(10); taskExecutor.setQueueCapacity(10); taskExecutor.afterPropertiesSet(); CountDownLatch countDownLatch = new CountDownLatch(20); this.startThreads(taskExecutor, countDownLatch, 20); while (countDownLatch.getCount() > 0) { Assert.assertEquals(10, taskExecutor.getPoolSize()); } }

De même, si nous avions défini queueCapactity sur zéro et démarré seulement dix tâches, nous aurions également dix threads dans notre ThreadPoolTaskExecutor .

5. Conclusion

ThreadPoolTaskExecutor est une abstraction puissante autour d'un java.util.concurrent.ThreadPoolExecutor , fournissant des options pour configurer corePoolSize , maxPoolSize et queueCapacity . Dans ce didacticiel, nous avons examiné les propriétés corePoolSize et maxPoolSize , ainsi que le fonctionnement de maxPoolSize en tandem avec queueCapacity , ce qui nous permet de créer facilement des pools de threads pour tous les cas d'utilisation.

Comme toujours, vous pouvez trouver le code disponible sur Github.