Java création de thread frais généraux
Sagesse populaire nous dit que la haute-volume de java enterprise applications devraient utiliser le thread de mise en commun, de préférence à de nouvelles zones de frai de threads de travail. L'utilisation de java.util.concurrent
fait de ce simple.
Il existe cependant des situations où la mise en pool de threads n'est pas un bon ajustement. L'exemple précis que je suis en train de lutte est l'utilisation de InheritableThreadLocal
, qui permet ThreadLocal
variables à "transmis" à tout donné naissance à des fils. Ce mécanisme de pauses lors de l'utilisation de pools de threads, depuis les threads de travail sont généralement pas disponible à partir de la demande de thread, mais sont pré-existants.
Maintenant, il ya des façons de contourner cela (le fil les habitants peuvent être explicitement passés), mais ce n'est pas toujours approprié ou pratique. La solution la plus simple consiste à engendrer de nouveaux threads de travail sur la demande, et de laisser InheritableThreadLocal
faire son travail.
Cela nous ramène à la question - si j'ai un site à haut volume, où la demande de l'utilisateur, les threads sont hors frai une demi-douzaine de threads de travail de chacun (c'est à dire non à l'aide d'un pool de threads), est-ce que ça va donner à la JVM d'un problème? Nous sommes potentiellement parler d'un couple de centaines de nouveaux threads créés chaque seconde, chacune d'une durée inférieure à une seconde. Faire moderne Jvm optimiser ce bien? Je me souviens des jours où l'objet de mise en commun est souhaitable dans Java, parce que la création de l'objet était cher. Ceci est depuis devenu inutile. Je me demande si la même chose s'applique à la mise en pool de threads.
J'avais de référence, si je savais ce qu'il faut mesurer, mais ma crainte est que les problèmes peuvent être plus subtile que ne peut être mesurée avec un profiler.
Remarque: la sagesse de l'aide de fil habitants n'est pas la question ici, donc merci de ne pas me proposer de ne pas les utiliser.
- J'allais suggérer que l'emballage de votre ThreadLocal dans une méthode d'accesseur serait probablement résoudre vos problèmes avec InheritableThreadLocal, mais vous ne semblez pas vouloir en entendre parler. De Plus, il semble que vous utilisez InheritableThreadLocal comme un out-of-band d'appel, qui, pour être honnête, apparaît comme une odeur de code.
- Aussi loin que les pools de threads aller, le principal avantage est contrôle: vous savez que vous n'aurez pas tout à coup essayer de rotation de 10 000 threads dans une seconde.
- Pour votre premier point, la ThreadLocals en question sont utilisés par les Printemps de la fève à la portée. C'est la façon dont des travaux du Printemps, et pas quelque chose que j'ai le contrôle. Pour votre deuxième point, la requête entrante threads sont limitées par tomcat pool de threads, de sorte que la limitation est inhérente à qui.
- Comment le Tomcat pool de threads de limiter le nombre de threads que vous créez? Vous décrire une application où "la demande de l'utilisateur threads [frayer] une demi-douzaine de threads de travail," et j'ai pensé que votre préoccupation était sur ces fils. Un bug et vous pourriez facilement avoir plus de 10,000 fils filés pour une seule requête.
- Concernant la raison pour laquelle vous avez besoin de ThreadLocal, cependant: il est valide, et une bonne chose à poster dans le message pour éviter les smart-ass commentaires 🙂
Vous devez vous connecter pour publier un commentaire.
Voici un exemple microbenchmark:
Les résultats sur une version 64 bits de Windows 7 32-bit Java de Sun 1.6.0_21 Client VM sur un Intel Core 2 Duo E6400 @2.13 GHz sont comme suit:
Conclusions: les Deux fils à faire le travail presque deux fois plus rapide qu'un, comme prévu depuis mon ordinateur est doté de deux cœurs. Mon ordinateur peut se reproduire près de 10000 threads par seconde, j'. e. de création de thread frais généraux est de 0,1 millisecondes. Donc, sur une telle machine, un couple de centaines de nouveaux threads par seconde pose négligeable, les frais généraux (comme on peut aussi le voir en comparant les chiffres dans les colonnes 2 et 100 threads).
Tout d'abord, cela dépend beaucoup de ce qui JVM vous utilisez. Le système d'exploitation doit également jouer un rôle important. En supposant que la JVM de Sun (Hm, faut-il encore l'appeler comme ça?):
Est un facteur majeur de la pile de la mémoire allouée à chaque thread, que vous pouvez régler à l'aide de la
-Xssn
paramètre de JVM - vous aurez envie d'utiliser la valeur la plus basse que vous pouvez sortir avec.Et c'est juste une supposition, mais je pense que "un couple de centaines de nouveaux threads à chaque seconde" est certainement au-delà de ce que la JVM est conçu pour gérer confortablement. Je soupçonne qu'un simple indice de référence va rapidement révéler unsubtle problèmes.
new Thread()
signifie être intéressant. Dans un cadre moderne JVM,new Object()
n'est pas toujours allouer la mémoire nouveau, il reprend déjà le garbage collector objets. Je me demande si il n'y a aucune raison pour que la JVM ne pouvais pas l'avoir caché, piscine interne de réutilisables fils, de sorte quenew Thread()
n'est pas nécessairement la création d'un nouveau thread du noyau. Vous obtiendrez effective du filetage de la mise en commun, sans avoir besoin d'une API pour cela.pour votre référence, vous pouvez utiliser JMeter + un profiler, ce qui devrait vous donner une vue globale sur le comportement dans ces lourds chargé de l'environnement. Juste le laisser fonctionner pendant une heure et surveiller la mémoire, cpu, etc. Si rien ne se brise et que le cpu(s) n'a pas de surchauffe, c'est ok 🙂
peut-être vous pouvez obtenir un thread pool, ou personnaliser (étendre) celui que vous utilisez en ajoutant un peu de code pour avoir les
InheritableThreadLocal
s définir à chaque fois qu'unThread
est acquise à partir du fil de la piscine.Chaque
Thread
a ces colis-privé propriétés:Vous pouvez utiliser ces (eh bien, avec la réflexion), en combinaison avec la
Thread.currentThread()
d'avoir le comportement souhaité. Cependant, c'est un peu ad-jarret, et en outre, je ne peux pas dire si elle (la réflexion) ne pas introduire encore plus de frais généraux que de créer les threads.@Async
au Printemps 3, qui découpler la mécanique de laCallable
de la logique métier. C'est très cool, mais cela signifie que vous n'obtenez pas l'accès à l'exécuteur lui-même, ou les tâches qui sont crées.Je me demande si il est nécessaire de frayer de nouveaux threads sur chaque demande de l'utilisateur si typique du cycle de vie est aussi courte que la seconde. Pourriez-vous utiliser un certain type de Notification/file d'Attente où vous frayer un nombre donné d' (démon)fils, et ils ont tous d'attendre jusqu'à ce qu'il y a un problème à résoudre. Si la tâche de la file d'attente devient longue, vous frayer des threads supplémentaires, mais pas sur un taux de 1-1. Il sera probablement effectuer de mieux que de frai des centaines de nouveaux threads dont les cycles de vie sont si courtes.
private ThreadLocal<T> local;
qui vous instancier chaque fois que le thread de Demande se réveille, et lors du traitement de chaque thread de travail, vous utilisezlocal.set()
/local.get()
, mais il est probable que j'ai mal compris votre problème.