FixedThreadPool vs CachedThreadPool: le moindre de deux maux

J'ai donc un programme qui génère des threads (~5-150) qui exécutent un tas de tâches. À l'origine, j'ai utilisé un FixedThreadPool parce que cette question similaire suggéré qu'ils étaient mieux adaptés pour les tâches de plus longue durée et avec ma connaissance très limitée de la multithreading, j'ai considéré la vie moyenne des fils (plusieurs minutes) " longue durée de vie ".

cependant, j'ai récemment ajouté la possibilité de générer des threads supplémentaires et le faire me porte au-dessus de la limite de thread que j'ai fixée. Dans ce cas, serait-il préférable de deviner et d'augmenter le nombre de threads que je peux autoriser ou de passer à un CachedThreadPool donc je n'ai pas de threads gaspillés?

essayer les deux à la fois à titre préliminaire, il n'y a pas semblent pour être une différence donc je suis enclin à aller avec le CachedThreadPool juste pour éviter les déchets. Toutefois, la durée de vie des filets dire j'aurais plutôt choisi un FixedThreadPool et juste face avec le solde non utilisé des threads? cette question donne l'impression que ces fils supplémentaires ne sont pas perdus, mais j'apprécierais la clarification.

72
demandé sur Ravindra babu 2013-07-31 01:05:09

3 réponses

un CachedThreadPool est exactement ce que vous devriez utiliser pour votre situation car il n'y a pas de conséquence négative à l'utilisation d'un pour les longs threads. Le commentaire dans le doc java selon lequel les logiciels CachedThreadPools conviennent aux tâches courtes suggère simplement qu'ils sont particulièrement appropriés dans de tels cas, et non pas qu'ils ne peuvent pas ou ne doivent pas être utilisés pour des tâches impliquant des tâches de longue durée.

pour en savoir plus, exécuteurs testamentaires.newCachedThreadPool et exécuteurs.newFixedThreadPool sont tous les deux soutenus par la même implémentation de pool de threads (au moins dans le JDK ouvert) juste avec des paramètres différents. Les différences étant juste leur thread minimum, maximum, thread kill time, et le type de file d'attente.

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>());
}

Un FixedThreadPool a ses avantages lorsque vous voulez bien de travailler avec un nombre fixe de threads, depuis lors, vous pouvez soumettre un nombre quelconque de tâches à l'exécuteur testamentaire de service tout en sachant que le nombre de threads sera maintenu au niveau spécifié. Si vous souhaitez explicitement d'augmenter le nombre de threads, alors ce n'est pas le bon choix.

cela signifie cependant que le seul problème que vous pouvez avoir avec le CachedThreadPool est en ce qui concerne la limitation du nombre de threads qui tournent simultanément. Le CachedThreadPool ne limitera pas pour vous, alors vous pouvez avoir besoin d'écrire votre propre code pour vous assurer que vous n'exécutez pas trop de threads. Cela dépend vraiment de la conception de votre demande et de la façon dont les tâches sont soumises au service d'exécuteur testamentaire.

87
répondu Trevor Freeman 2016-07-17 06:11:56

les deux FixedThreadPool et CachedThreadPool sont des maux dans les applications très chargées.

CachedThreadPool est plus dangereux que FixedThreadPool

si votre application est très chargée et demande une faible latence, mieux de se débarrasser des deux options en raison des inconvénients ci-dessous

  1. la Surabondance de la nature de la tâche de la file d'attente : Il peut causer de mémoire ou de temps de latence élevé
  2. longs fils de course sera la cause CachedThreadPool d'aller hors de contrôle sur la création de Thread

comme vous savez que les deux sont des maux, un moindre mal ne fait pas de bien. Prefer ThreadPoolExecutor , qui fournit un contrôle granulaire sur de nombreux paramètres.

  1. définir la file d'attente des tâches comme une file d'attente bornée pour avoir un meilleur contrôle
  2. Ont droit RejectionHandler - Votre propre RejectionHandler ou gestionnaires par Défaut fournies par le JDK
  3. si vous avez quelque chose à faire avant/après l'achèvement de la tâche, outrepasser beforeExecute(Thread, Runnable) et afterExecute(Runnable, Throwable)
  4. Remplacer ThreadFactory si la thread de personnalisation est nécessaire
  5. Contrôle de la taille du pool de Threads de manière dynamique au moment de l'exécution ( liées SE question : Dynamique de Pool de Threads )
29
répondu Ravindra babu 2017-10-17 14:46:12

J'ai donc un programme qui génère des threads (~5-150) qui exécutent un tas de tâches.

êtes-vous sûr de comprendre comment les threads sont traités par votre système D'exploitation et le matériel de votre choix? Comment Java établit la correspondance entre les threads et les threads OS, comment cela établit la correspondance entre les threads et les threads CPU, etc.? Je demande parce que créer 150 threads à l'intérieur dans un JRE n'a de sens que si vous avez des noyaux/threads de CPU massifs en dessous, ce qui n'est probablement pas le cas. En fonction de L'OS et de la mémoire vive utilisés, la création de plus de n threads peut même entraîner la fin de votre JRE à cause d'erreurs OOM. Donc, vous devriez vraiment distinguer entre les fils et le travail à faire par ces fils, combien de travail vous êtes même capable de traiter, etc.

et c'est le problème avec CachedThreadPool: cela n'a pas de sens de faire la queue dans des threads qui ne peuvent pas fonctionner parce que vous n'avez que 2 cœurs CPU capables de traiter ces threads. Si vous finissez avec 150 threads programmés vous pourriez créer beaucoup de frais généraux inutiles pour les programmeurs utilisés dans Java et L'OS pour les traiter en même temps. C'est tout simplement impossible si vous n'avez que 2 cœurs CPU, à moins que vos threads n'attendent l'entrée/sortie ou telle chose tout le temps. Mais même dans ce cas, beaucoup de fils créeraient beaucoup d'entrées / sorties...

et que le problème ne se produit pas avec FixedThreadPool, créé avec par exemple 2 + n threads, où n est raisonnable bas bien sûr, parce qu'avec ce matériel et les ressources OS sont utilisées avec beaucoup moins de frais généraux pour gérer les threads qui ne peuvent pas fonctionner de toute façon.

5
répondu Thorsten Schöning 2016-07-10 10:31:23