Exécuteur.newCachedThreadPool() par rapport à des Exécuteurs testamentaires.newFixedThreadPool()

newCachedThreadPool() rapport newFixedThreadPool()

Quand devrais-je utiliser l'un ou l'autre? Quelle stratégie est la meilleure en termes d'utilisation des ressources?

121
demandé sur dimo414 2009-06-04 12:55:40

7 réponses

je pense que les docs expliquent assez bien la différence et l'usage de ces deux fonctions:

newFixedThreadPool

crée un filet qui réutilise un nombre fixe de threads désactivés une file d'attente illimitée partagée. À tout point, à la plupart des nthreads fils seront être actif tâches de traitement. Si des tâches supplémentaires sont soumises lorsque tous les threads sont actifs, ils attendront dans la file d'attente jusqu'à ce qu'un fil est disponible. Si un fil se termine en raison d'un échec lors de l'exécution avant l'arrêt, un nouveau prendre sa place si nécessaire pour exécuter les tâches à venir. Les discussions dans le piscine existera jusqu'à ce qu'il soit explicitement arrêt.

newCachedThreadPool

crée une piscine de fil qui crée de nouvelles threads au besoin, mais réutilisera fils déjà construits lorsque ils sont disponibles. Ces piscines généralement d'améliorer les performances de programmes qui exécutent de nombreux de courte durée tâches asynchrones. Les appels à exécuter réutilisation déjà construits les threads si disponible. Si aucune fil est disponible, un nouveau thread être créé et ajouté à la piscine. Fils qui n'ont pas été utilisés pour soixante secondes sont terminées et supprimé à partir du cache. Ainsi, une piscine qui reste inactif assez longtemps ne consommez pas de ressources. Notez que les piscines avec des propriétés similaires, mais différents détails (par exemple, paramètres de temporisation) peuvent être créés en utilisant les constructeurs ThreadPoolExecutor.

en termes de ressources, le newFixedThreadPool maintiendra tous les threads actifs jusqu'à ce qu'ils soient explicitement terminés. Dans les Threads newCachedThreadPool qui n'ont pas été utilisés depuis soixante secondes sont terminés et retirés du cache.

compte tenu de cela, la consommation de ressources dépendra très beaucoup dans la situation. Par exemple, Si vous avez un grand nombre de tâches longues, je dirais que la FixedThreadPool . Quant au CachedThreadPool , les docs disent que"ces pools amélioreront typiquement la performance des programmes qui exécutent de nombreuses tâches asynchrones de courte durée".

158
répondu bruno conde 2016-07-21 13:55:59

juste pour compléter les autres réponses, je voudrais citer Effective Java, 2e édition, par Joshua Bloch, chapitre 10, Point 68 :

" choisir le service d'exécuteur pour une application particulière peut être délicat. Si vous écrivez un petit programme , ou un serveur légèrement chargé , en utilisant exécuteurs.new-CachedThreadPool est généralement un bon choix , car il exige aucune configuration et généralement " fait la bonne chose."Mais un pool de threads en cache est pas un bon choix pour un serveur de production lourdement chargé !

Dans un mise en cache du pool de threads , soumis tâches ne sont pas mis en file d'attente mais immédiatement transmis à un thread d'exécution. Si aucun thread n'est disponible, un nouveau est créé . Si un serveur est si lourd chargé que tous ses CPU sont pleinement utilisés, et plus de tâches arrivent, plus de threads seront créés, ce qui ne fera qu'empirer les choses.

par conséquent, dans un serveur de production chargé , vous êtes beaucoup mieux en utilisant des exécuteurs .newFixedThreadPool , qui vous donne un pool avec un nombre fixe de threads, ou en utilisant directement la classe ThreadPoolExecutor, pour un contrôle maximum. "

53
répondu Louis F. 2015-12-15 09:21:44

si vous voyez le code dans le grepcode, vous verrez, ils appellent ThreadPoolExecutor. interne et la mise en place de leurs propriétés. Vous pouvez créer votre avoir un meilleur contrôle de votre exigence.

public static ExecutorService newFixedThreadPool(int nThreads) {
   return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
10
répondu krmanish007 2016-09-17 18:28:34

c'est exact, Executors.newCachedThreadPool() n'est pas un bon choix pour le code serveur qui sert plusieurs clients et des requêtes simultanées.

pourquoi? Il y a essentiellement deux problèmes (liés) avec elle:

  1. c'est illimité, ce qui veut dire que vous ouvrez la porte à quiconque pour paralyser votre JVM en injectant simplement plus de travail dans le service (attaque DoS). Les Threads consomment une quantité non négligeable de mémoire et augmentent également la mémoire consommation basée sur leur travail en cours, il est donc assez facile de renverser un serveur de cette façon (sauf si vous avez d'autres disjoncteurs en place).

  2. le problème non limité est exacerbé par le fait que l'exécuteur testamentaire est dirigé par un SynchronousQueue ce qui signifie qu'il y a un transfert direct entre le donneur d'ordre et le pool de fils. Chaque nouvelle tâche créera un nouveau thread si tous les threads existants sont occupés. C'est généralement une mauvaise stratégie pour le code serveur. Lorsque L'unité centrale est saturée, les tâches existantes prennent plus de temps à finir. Encore plus de tâches sont soumises et plus de threads créés, de sorte que les tâches prennent de plus en plus de temps à compléter. Lorsque le CPU est saturé, plus de threads n'est certainement pas ce dont le serveur a besoin.

Voici mes recommandations:

utiliser un pool de threads de taille fixe exécuteurs.newFixedThreadPool ou un ThreadPoolExecutor. avec un nombre maximum fixé de filets;

7
répondu Prashant Gautam 2016-09-05 11:43:25

si vous n'êtes pas inquiet de la file d'attente illimitée des tâches appelables/exécutables , vous pouvez utiliser l'une d'elles. Comme suggéré par bruno, je préfère aussi newFixedThreadPool à newCachedThreadPool entre ces deux.

mais ThreadPoolExecutor offre des caractéristiques plus flexibles par rapport à la fois newFixedThreadPool ou newCachedThreadPool

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

avantages:

  1. Vous avez le plein contrôle sur BlockingQueue taille de. Il n'est pas sans limites contrairement aux deux options précédentes. Je ne vais pas sortir de l'erreur de mémoire en raison de l'énorme amoncellement de tâches appelables/exécutables en attente dans la turbulence inattendue dans le système.

  2. , Vous pouvez mettre en œuvre personnalisée le Rejet de la manipulation de la politique OU des politiques:

    1. dans le par défaut ThreadPoolExecutor.AbortPolicy , le gestionnaire lance un runtime Rejetedexecutionexception lors du rejet.

    2. dans ThreadPoolExecutor.CallerRunsPolicy , le thread qui invoque execute lui-même exécute la tâche. Il s'agit d'un mécanisme simple de contrôle de la rétroaction qui ralentira le rythme de présentation des nouvelles tâches.

    3. Dans ThreadPoolExecutor.DiscardPolicy , une tâche qui ne peut être exécutée est tout simplement abandonné.

    4. Dans ThreadPoolExecutor.DiscardOldestPolicy , si l'exécuteur testamentaire n'est pas arrêté, la tâche à la tête de la file d'attente de travail est supprimé, et l'exécution est répétée (qui peut échouer à nouveau, à l'origine de ce être répétée.)

  3. vous pouvez mettre en œuvre custom Thread factory pour les cas d'utilisation ci-dessous:

    1. pour définir un nom de fil plus descriptif
    2. pour définir le statut de démon thread
    3. pour définir la priorité du fil
7
répondu Ravindra babu 2016-09-06 06:13:34

vous devez utiliser newCachedThreadPool seulement lorsque vous avez des tâches asynchrones de courte durée comme indiqué dans Javadoc, si vous soumettez des tâches qui prennent plus de temps à traiter, vous finirez par créer trop de threads. Vous pouvez atteindre 100% CPU si vous soumettez des tâches à long terme à un rythme plus rapide à newCachedThreadPool ( http://rashcoder.com/be-careful-while-using-executors-newcachedthreadpool / ).

3
répondu Dhanaraj Durairaj 2015-09-15 12:04:07

je fais quelques tests rapides et j'ai les résultats suivants:

1) en cas D'utilisation de Synchronequeue:

après que les threads atteignent la taille maximale, tout nouveau travail sera rejeté avec l'exception comme ci-dessous.

Exception dans le fil" main " java.util.simultané.RejectedExecutionException: tâche java.util.simultané.FutureTask@3fee733d rejeté de java.util.simultané.ThreadPoolExecutor@5acf9800[en cours d'Exécution, piscine taille = 3, threads actifs = 3, les tâches en file d'attente = 0, les tâches terminées = 0]

à java.util.simultané.ThreadPoolExecutor $ AbortPolicy.rejet de l'exécution (ThreadPoolExecutor.java: 2047)

2) Si vous utilisez LinkedBlockingQueue:

les filets ne passent jamais de la taille minimale à la taille maximale, ce qui signifie que le filet est de taille fixe comme la taille minimale.

0
répondu Mike Lin 2018-03-12 21:18:58