Mon utilisation de ThreadLocal
Dans mes classes Java, il m'arrive de faire usage d'un ThreadLocal
principalement comme un moyen d'éviter la création d'un objet:
@net.jcip.annotations.ThreadSafe
public class DateSensitiveThing {
private final Date then;
public DateSensitiveThing(Date then) {
this.then = then;
}
private static final ThreadLocal<Calendar> threadCal = new ThreadLocal<Calendar>() {
@Override
protected Calendar initialValue() {
return new GregorianCalendar();
}
};
public Date doCalc(int n) {
Calendar c = threadCal.get();
c.setTime(this.then):
// use n to mutate c
return c.getTime();
}
}
Je fais cela pour la bonne raison - GregorianCalendar
est l'un de ces glorieusement dynamique, mutable, non thread-safe objets, qui fournit un service à travers de multiples appels, plutôt que de représenter une valeur. En outre, il est considéré comme "cher" pour instancier (si cela est vrai ou non n'est pas le point de cette question). (Dans l'ensemble, j'ai vraiment l'admirer :-))
Comment Tomcat Whinges
Cependant, si j'utilise une classe dans un environnement qui les pools de threads - et où ma demande n'est pas dans le contrôle du cycle de vie de ces threads - ensuite, il ya le potentiel pour des fuites de mémoire. Un environnement de Servlet est un bon exemple.
En fait, Tomcat 7 whinges comme quand une webapp est arrêté:
GRAVE: L'application web [] créé un ThreadLocal avec clé de type [org.apache.xmlbeans.impl.magasin.CharUtil$1] (valeur [org.apache.xmlbeans.impl.magasin.CharUtil$1@2aace7a7]) et une valeur de type [java.lang.réf.SoftReference] (valeur [java.lang.ref.SoftReference@3d9c9ad4]), mais pas réussi à le retirer lors de la l'application web a été arrêté. Les Threads vont être renouvelés plus de temps d'essayer d'éviter une probable fuite de mémoire. Dec 13, 2012 12:54:30 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
(Même pas mon code de le faire, dans ce cas particulier).
Qui est à blâmer?
Cela ne semble pas juste. Tomcat est de blâmer moi (ou l'utilisateur de ma classe) pour faire la bonne chose.
En fin de compte, c'est parce que Tomcat veut réutiliser les threads, il m'a offert, pour d'autres applications web. (Ugh - je me sens sale.) Probablement, ce n'est pas un grand politique sur Tomcat, en partie parce que les threads a/cause de l'état - ne partagez pas 'em entre les applications.
Cependant, cette politique est d'au moins commun, même s'il n'est pas souhaitable. J'ai l'impression que je suis obligé - en ThreadLocal
utilisateur, pour fournir un moyen pour les élèves de ma classe de "libérer" les ressources qui ma classe a attaché à plusieurs fils.
Mais ce qu'il faut faire à ce sujet?
Qu'est-ce que la bonne chose à faire ici?
Pour moi, il semble que le moteur de servlet fil de la réutilisation de la politique est en contradiction avec l'intention d' ThreadLocal
.
Mais je devrais peut-être mettre en place un mécanisme pour permettre aux utilisateurs de dire "retire-toi, le mal de thread spécifique de l'état associé à cette classe, même si je ne suis pas en mesure de laisser le fil de mourir et de laisser GC faire sa chose?". Est-il encore possible pour moi de faire cela? Je veux dire, c'est pas comme si je peux m'arranger pour ThreadLocal#remove()
d'être appelé sur chacun des Fils qui vit ThreadLocal#initialValue()
, à un certain moment dans le passé. Ou est-il un autre moyen?
Ou devrais-je dire à mes utilisateurs "aller et vous obtenez un décent chargeur de classe et le pool de threads mise en œuvre"?
EDIT#1: Clarifier la façon dont threadCal
est utilisé dans un vanailla classe utilitaire qui ignorent fil des cycles de vie
EDIT#2: correction d'un thread d'un problème de sécurité en DateSensitiveThing