[Série JUC] Compréhension approfondie du pool de threads

Le but de l' utilisation du pool de threads du pool de threads :

  • Réduisez la consommation de ressources: la création et la destruction de threads occuperont les ressources système
  • Améliorez la vitesse de réponse: il faut du temps pour créer et détruire des threads
  • Gestion centralisée pratique: afin d'éviter l'abus du multi-threading, il y a une place pour une gestion unifiée

Dans le "Manuel de développement Java d'Alibaba", il est indiqué que les ressources de thread doivent être fournies via le pool de threads et qu'il n'est pas autorisé de créer des threads dans l'affichage de l'application; et que le pool de threads n'est pas autorisé à être créé à l'aide des exécuteurs, et doit être créé via ThreadPoolExecutor, car le framework Executor dans jdk fournit Tels que newFixedThreadPool (), newSingleThreadExecutor (), newCachedThreadPool () et d'autres méthodes pour créer des pools de threads, mais ils ne sont toujours pas assez flexibles.

1 Règles de définition du nombre de threads

Cependant, en fonction de l'entreprise, les tâches peuvent être divisées en tâches gourmandes en E / S et en calcul intensif. Il y aura des règles différentes pour le nombre de threads que nous définissons pour différents types:
le nombre de pools de threads doit être aussi petit que possible, ce qui est approximativement égal au nombre de cœurs de processeur.

  • Pour IO-intensive: le nombre de threads dans le pool de threads est relativement grand, approximativement égal au nombre de cœurs CPU * 2.
  • Pour les calculs intensifs: le nombre de pools de threads doit être aussi petit que possible, approximativement égal au nombre de cœurs de processeur.

2 Principe du pool de threads

Le principe de réalisation du pool de threads java est en fait très simple, il s'agit d'un workerSet de collecte de threads et d'une file d'attente de blocage workQueue. Lors de la soumission d'une tâche au pool de threads, le pool de threads place d'abord la tâche dans le workQueue, et les threads du workerSet obtiennent en permanence des threads de workQueue et les exécutent. Lorsqu'il n'y a pas de tâche dans la file d'attente de travail, le travailleur bloque jusqu'à ce qu'il y ait une tâche dans la file d'attente, puis la retire pour continuer l'exécution.
Insérez la description de l'image ici

Processus de pool à 3 threads

Lorsqu'une tâche est soumise au pool de threads, le flux d'exécution approximatif est le suivant:

  • Le pool de threads déterminera d'abord si le nombre de threads en cours d'exécution est inférieur à corePoolSize. Si tel est le cas, un nouveau thread de travail est créé pour exécuter la tâche. Si toutes les tâches sont en cours d'exécution, passez à la deuxième étape.
  • Déterminez si BlockingQueue est plein et, s'il n'est pas plein, placez le thread dans BlockingQueue. Sinon, passez à la troisième étape
  • Créez un nouveau thread jusqu'à ce que le nombre de threads atteigne le maximumPoolSize, si la création d'un nouveau thread de travail entraînera le dépassement du nombre de threads en cours d'exécution du maximumPoolSize, remettez-le à RejectedExecutionHandler pour gérer la tâche

4 Paramètres du pool de threads

  • corePoolSize: le nombre de threads principaux. Lors de la soumission d'une tâche au pool de threads, si le nombre de threads du pool de threads actuel est inférieur à corePoolSize, de nouveaux threads seront créés pour effectuer des tâches, sachant que le nombre de threads est égal à corePoolSize. Si le nombre actuel de threads est corePoolSize, les tâches qui continuent à être soumises sont enregistrées dans la file d'attente de blocage et en attente d'être exécutées; si la méthode prestartAllCoreThreads () du pool de threads est exécutée, le pool de threads créera et démarrera tous les core threads à l'avance.
  • workQueue: file d'attente de blocage utilisée pour stocker les tâches en attente d'exécution. Les files d'attente de blocage suivantes sont fournies dans le JDK
    • ArrayBlockingQueue: file d'attente de blocage bornée basée sur la structure du tableau, trier les tâches par FIFO
    • LinkedBlockingQueue: en fonction du blocage de la structure de la liste liée, les tâches sont triées par FIFO et le débit est généralement élevé. Lorsque la capacité n'est pas spécifiée, la capacité par défaut est Integer.MAX_VALUE.
    • SynchronousQueue: une file d'attente de blocage sans éléments, chaque opération d'insertion doit attendre qu'un autre thread appelle l'opération de suppression, sinon l'opération d'insertion a été bloquée et le débit est généralement supérieur à LinkedBlockingQueue
    • PriorityBlockingQueue: file d'attente de blocage illimitée avec priorité
    • DelayQueue: similaire à PriorityBlockingQueue, il s'agit d'une file d'attente de blocage de priorité illimitée implémentée par un tas binaire. Tous les éléments sont nécessaires pour implémenter l'interface Delayed. Les tâches sont extraites de la file d'attente pendant le délai d'exécution, et le temps n'est pas suffisant.
  • maximumPoolSize: nombre maximal de threads autorisés dans le pool de threads. Si la file d'attente de blocage actuelle est pleine, continuez à soumettre des tâches au pool de threads. Si le nombre actuel de threads dans le pool de threads est inférieur à la valeur maximumPoolSize, elle continuera. pour créer des threads pour effectuer des tâches. Lorsque la file d'attente de blocage est une file d'attente illimitée, maximumPoolSize n'a aucun effet, car les threads qui ne peuvent pas être soumis au pool de threads principaux continueront à être placés dans la file d'attente de travail.
  • keepAliveTime: le temps de survie d'un thread non-core lorsqu'il est inactif, c'est-à-dire le temps pendant lequel le thread continue de survivre lorsque le thread n'a pas d'exécution de tâche.
  • unité: unité keepAliveTime
  • threadFactory: fabrique de création de threads. Grâce à une fabrique de threads personnalisée, un nom de thread reconnaissable peut être défini pour chaque thread nouvellement créé. La valeur par défaut est DefaultThreadFactory.
  • gestionnaire: pool de threads et stratégie de saturation. Lorsque la file d'attente de blocage est pleine, le nombre de threads dans le pool de threads est supérieur au maximumPoolSize et il n'y en a aucun inactif. Si vous continuez à soumettre des tâches, vous devez adopter une stratégie pour gérer les tâches que ces threads ne peuvent pas gérer. Le pool de threads propose quatre stratégies:
    • AbortPolicy: lancer une exception directement, la politique par défaut;
    • CallerRunsPolicy: utilisez le thread de l'appelant pour effectuer des tâches;
    • DiscardOldentPolicy: Ignorez la tâche supérieure de la file d'attente de blocage et exécutez la tâche en cours;
    • DiscardPolicy: rejette directement la tâche.
      Nous pouvons également implémenter l'interface RejectedExecutionHandler en fonction du scénario d'application réel et personnaliser la stratégie de saturation, comme les tâches de journalisation ou les tâches qui ne peuvent pas être traitées par le stockage persistant.

5 Analyse du code source de l'exécuteur

FixedThreadPool (pool de threads de longueur fixe)

Insérez la description de l'image ici

Caractéristiques:

  • LinkedBlockingQueue est utilisé et la longueur n'est pas spécifiée

insuffisant:

  • Étant donné que la valeur par défaut est Integer.MAX_VALUE, il peut consommer beaucoup de mémoire, voire même MOO

ScheduledThreadPool (pool de threads chronométrés)

Insérez la description de l'image ici

Caractéristiques:

  • LinkedBlockingQueue est utilisé et la longueur n'est pas spécifiée

insuffisant:

  • Étant donné que la valeur par défaut est Integer.MAX_VALUE, il peut consommer beaucoup de mémoire, voire même MOO

CacheThreadPool (pool de threads pouvant être mis en cache)

Insérez la description de l'image ici

Caractéristiques:

  • La valeur maximale de maximumPoolSize est Integer.MAX_VALUE, car son numéro de pool de threads de base est 0, donc lorsque le thread est inactif pendant 60 secondes, il sera recyclé. Dans les cas extrêmes, il ne contiendra aucune ressource de thread.

insuffisant:

  • Peut provoquer la création de nombreux threads, même MOO

SingleThreadExecutor (pool de threads uniques)

Insérez la description de l'image ici

Caractéristiques:

  • Il n'y a qu'un seul thread principal. Si le thread se termine anormalement, une nouvelle tâche de thread sera créée pour continuer la tâche. Le seul thread peut garantir l'exécution séquentielle des tâches soumises, à l'aide de la file d'attente illimitée LinkedBlockingQueue.

insuffisant:

  • En raison de l'utilisation de files d'attente illimitées, SingleThreadPool ne refusera jamais, c'est-à-dire que la stratégie de saturation n'est pas valide

6 pool de threads personnalisés

Après avoir lu le code source, nous avons constaté que bien que quatre implémentations de pool de threads soient fournies, elles présentent toutes certains inconvénients et de nombreux éléments ne peuvent pas être définis librement. Par conséquent, Ali ne recommande pas d'utiliser Executor pour une raison. ci-dessous. Pool de threads
Insérez la description de l'image ici

Description:

  • Nombre de fils de base: 5
  • Nombre maximum de threads: 9
  • Temps de survie inactif des threads non essentiels: 20 s
  • File d'attente des tâches: ArrayBlockingQueue de longueur 1
    Insérez la description de l'image ici

Description:
exécutez 10 tâches en continu et le temps d'exécution de chaque tâche est de 10 s

Effet:
Tout d'abord, 5 threads principaux seront utilisés, puis la sixième tâche sera placée dans la file d'attente des tâches. Comme la longueur de la file d'attente est de 1, lorsque les tâches suivantes arriveront, il sera jugé si le nombre maximum de threads a été atteint, donc la 7ème ~ 10ème tâche Cela obligera le pool de threads à créer le nombre maximum de threads à 9, puis après 10 secondes, il y aura des threads inactifs, puis exécutera la sixième tâche, l'effet d'exécution est comme indiqué dans la figure ci-dessous .
Insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_41979344/article/details/113483681
conseillé
Classement