Taille du pool principal vs taille maximale du pool dans ThreadPoolExecutor

Quelle est la différence entre la taille du pool principal et la taille maximale du pool lorsque l’on parle de ThreadPoolExecutor? Peut-on l’expliquer à l’aide d’un exemple?

    De cet article de blog :

    Prenons cet exemple. La taille du pool de threads de départ est 1, la taille du pool de base est 5, la taille maximale du pool est 10 et la queue 100.

    Au fur et à mesure de l’arrivée des requêtes, les threads seront créés jusqu’à 5, puis les tâches seront ajoutées à la queue jusqu’à ce qu’elles atteignent 100. Lorsque la queue est pleine, de nouveaux threads seront créés jusqu’à maxPoolSize . Une fois que tous les threads sont utilisés et que la queue est complète, les tâches seront rejetées. À mesure que la queue diminue, le nombre de threads actifs diminue également.

    De la doc :

    Lorsqu’une nouvelle tâche est soumise dans la méthode execute (java.lang.Runnable), et que moins de threads que corePoolSize sont en cours d’exécution, un nouveau thread est créé pour gérer la demande, même si d’autres threads de travail sont inactifs. S’il y a plus de corePoolSize mais moins de threads maximumPoolSize, un nouveau thread sera créé uniquement si la queue est pleine.

    En outre:

    En définissant corePoolSize et maximumPoolSize de la même manière, vous créez un pool de threads de taille fixe. En définissant maximumPoolSize sur une valeur non limitée telle que Integer.MAX_VALUE, vous autorisez le pool à gérer un nombre arbitraire de tâches simultanées. Le plus souvent, les tailles de pool principale et maximale sont définies uniquement lors de la construction, mais elles peuvent également être modifiées dynamicment à l’aide de setCorePoolSize (int) et de setMaximumPoolSize (int).

    Si vous décidez de créer un ThreadPoolExecutor manuellement au lieu d’utiliser la classe de fabrique Executors , vous devrez en créer et en configurer un en utilisant l’un de ses constructeurs. Le constructeur le plus complet de cette classe est:

     public ThreadPoolExecutor( int corePoolSize, int maxPoolSize, long keepAlive, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler ); 

    Comme vous pouvez le voir, vous pouvez configurer:

    • La taille du pool principal (la taille que le pool de threads essaiera de conserver).
    • La taille maximale de la piscine.
    • Le temps de maintien en vie, qui est une période au bout de laquelle un thread inactif peut être supprimé.
    • La queue de travail pour effectuer des tâches en attente d’exécution.
    • La politique à appliquer lorsqu’une soumission de tâche est rejetée.

    Limiter le nombre de tâches en attente

    Limiter le nombre de tâches simultanées en cours d’exécution, dimensionner votre pool de threads, représente un avantage considérable pour votre application et son environnement d’exécution en termes de prévisibilité et de stabilité: une création de threads illimitée finira par épuiser les ressources d’exécution. , de graves problèmes de performance pouvant entraîner une instabilité de l’application.

    C’est une solution à une partie du problème: vous plafonnez le nombre de tâches en cours d’exécution, mais vous ne limitez pas le nombre de tâches pouvant être soumises et mises en queue pour une exécution ultérieure. L’application connaîtra une pénurie de ressources plus tard, mais elle le rencontrera éventuellement si le taux de soumission dépasse systématiquement le taux d’exécution.

    La solution à ce problème est la suivante: Fournir une queue de blocage à l’exécuteur pour contenir les tâches en attente. Si la queue se remplit, la tâche soumise sera “rejetée”. Le RejectedExecutionHandler est appelé lorsqu’une soumission de tâche est rejetée, et c’est pourquoi le verbe rejeté a été cité dans l’élément précédent. Vous pouvez implémenter votre propre politique de rejet ou utiliser l’une des stratégies intégrées fournies par la structure.

    Les politiques de rejet par défaut font que l’exécuteur lance une RejectedExecutionException . Cependant, d’autres politiques intégrées vous permettent de:

    • Jeter un travail en silence.
    • Jeter le travail le plus ancien et essayer de soumettre à nouveau le dernier.
    • Exécutez la tâche rejetée sur le thread de l’appelant.

    Si vous exécutez des threads> corePoolSize & , créez un nouveau thread si la queue totale des tâches est pleine et qu’une nouvelle queue arrive.

    Form doc: (S’il y a plus de corePoolSize mais moins de threads maximumPoolSize , un nouveau thread sera créé uniquement si la file est pleine.)

    Maintenant, prenons un exemple simple,

     ThreadPoolExecutor executorPool = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue(50)); 

    Ici, 5 est le corePoolSize – signifie que Jvm créera un nouveau thread pour la nouvelle tâche pour les 5 premières tâches. et d’autres tâches seront ajoutées à la queue jusqu’à ce que la queue soit saturée (50 tâches).

    10 est le maxPoolSize – JVM peut créer un maximum de 10 threads. Signifie que s’il y a déjà 5 tâches / threads en cours d’exécution et que la queue est pleine avec 50 tâches en attente et qu’une nouvelle requête / tâche arrive dans la queue, JVM crée un nouveau thread jusqu’à 10 (nombre total de threads = 5 + nouveau 5) ;

    new ArrayBlockingQueue (50) = taille totale de la queue – elle peut mettre en queue 50 tâches.

    une fois que les 10 threads sont en cours d’exécution et si une nouvelle tâche arrive, cette nouvelle tâche sera rejetée.

    Règles de création de threads en interne par SUN:

    1. Si le nombre de threads est inférieur à celui de corePoolSize, créez un nouveau thread pour exécuter une nouvelle tâche.

    2. Si le nombre de threads est égal (ou supérieur) au corePoolSize, placez la tâche dans la queue.

    3. Si la queue est pleine et que le nombre de threads est inférieur à la valeur maxPoolSize, créez un nouveau thread pour exécuter les tâches.

    4. Si la queue est pleine et que le nombre de threads est supérieur ou égal à maxPoolSize, rejetez la tâche.

    Hope, This is HelpFul .. et s’il vous plaît corrigez-moi si je me trompe …

    Vous pouvez trouver la définition des termes corepoolsize et maxpoolsize dans le javadoc. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html

    Le lien ci-dessus a la réponse à votre question. Cependant, juste pour que ce soit clair. L’application continuera à créer des threads jusqu’à ce qu’elle atteigne le corePoolSize. Je pense que l’idée ici est que ces nombreux threads devraient être suffisants pour gérer l’afstream de tâches. Si une nouvelle tâche intervient après la création des threads corePoolSize, les tâches seront mises en queue. Une fois la queue pleine, l’exécuteur commencera à créer de nouveaux threads. C’est un peu équilibré. Cela signifie essentiellement que l’afstream de tâches dépasse la capacité de traitement. Ainsi, Executor va commencer à créer de nouveaux threads jusqu’à ce qu’il atteigne le nombre maximum de threads. Encore une fois, un nouveau thread sera créé si et seulement si la queue est pleine.

    Bonne explication dans ce blog:

    Illustration

     public class ThreadPoolExecutorExample { public static void main (Ssortingng[] args) { createAndRunPoolForQueue(new ArrayBlockingQueue(3), "Bounded"); createAndRunPoolForQueue(new LinkedBlockingDeque<>(), "Unbounded"); createAndRunPoolForQueue(new SynchronousQueue(), "Direct hand-off"); } private static void createAndRunPoolForQueue (BlockingQueue queue, Ssortingng msg) { System.out.println("---- " + msg + " queue instance = " + queue.getClass()+ " -------------"); ThreadPoolExecutor e = new ThreadPoolExecutor(2, 5, Long.MAX_VALUE, TimeUnit.NANOSECONDS, queue); for (int i = 0; i < 10; i++) { try { e.execute(new Task()); } catch (RejectedExecutionException ex) { System.out.println("Task rejected = " + (i + 1)); } printStatus(i + 1, e); } e.shutdownNow(); System.out.println("--------------------\n"); } private static void printStatus (int taskSubmitted, ThreadPoolExecutor e) { StringBuilder s = new StringBuilder(); s.append("poolSize = ") .append(e.getPoolSize()) .append(", corePoolSize = ") .append(e.getCorePoolSize()) .append(", queueSize = ") .append(e.getQueue() .size()) .append(", queueRemainingCapacity = ") .append(e.getQueue() .remainingCapacity()) .append(", maximumPoolSize = ") .append(e.getMaximumPoolSize()) .append(", totalTasksSubmitted = ") .append(taskSubmitted); System.out.println(s.toString()); } private static class Task implements Runnable { @Override public void run () { while (true) { try { Thread.sleep(1000000); } catch (InterruptedException e) { break; } } } } } 

    Sortie:

     ---- Bounded queue instance = class java.util.concurrent.ArrayBlockingQueue ------------- poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 1 poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 2 poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2, maximumPoolSize = 5, totalTasksSubmitted = 3 poolSize = 2, corePoolSize = 2, queueSize = 2, queueCapacity = 1, maximumPoolSize = 5, totalTasksSubmitted = 4 poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5 poolSize = 3, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6 poolSize = 4, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7 poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8 Task rejected = 9 poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9 Task rejected = 10 poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10 -------------------- ---- Unbounded queue instance = class java.util.concurrent.LinkedBlockingDeque ------------- poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 1 poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 2 poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2147483646, maximumPoolSize = 5, totalTasksSubmitted = 3 poolSize = 2, corePoolSize = 2, queueSize = 2, queueRemainingCapacity = 2147483645, maximumPoolSize = 5, totalTasksSubmitted = 4 poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 2147483644, maximumPoolSize = 5, totalTasksSubmitted = 5 poolSize = 2, corePoolSize = 2, queueSize = 4, queueRemainingCapacity = 2147483643, maximumPoolSize = 5, totalTasksSubmitted = 6 poolSize = 2, corePoolSize = 2, queueSize = 5, queueRemainingCapacity = 2147483642, maximumPoolSize = 5, totalTasksSubmitted = 7 poolSize = 2, corePoolSize = 2, queueSize = 6, queueRemainingCapacity = 2147483641, maximumPoolSize = 5, totalTasksSubmitted = 8 poolSize = 2, corePoolSize = 2, queueSize = 7, queueRemainingCapacity = 2147483640, maximumPoolSize = 5, totalTasksSubmitted = 9 poolSize = 2, corePoolSize = 2, queueSize = 8, queueRemainingCapacity = 2147483639, maximumPoolSize = 5, totalTasksSubmitted = 10 -------------------- ---- Direct hand-off queue instance = class java.util.concurrent.SynchronousQueue ------------- poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 1 poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 2 poolSize = 3, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 3 poolSize = 4, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 4 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5 Task rejected = 6 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6 Task rejected = 7 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7 Task rejected = 8 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8 Task rejected = 9 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9 Task rejected = 10 poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10 -------------------- Process finished with exit code 0