Quand dois-je utiliser un ThreadLocal
variable ?
Comment l'utilise-t-on ?
Quand dois-je utiliser un ThreadLocal
variable ?
Comment l'utilise-t-on ?
Une utilisation possible (et commune) est lorsque vous avez un objet qui n'est pas thread-safe, mais que vous voulez éviter de synchroniser l'accès à cet objet (je vous regarde, SimpleDateFormat ). Au lieu de cela, donnez à chaque thread sa propre instance de l'objet.
Par exemple :
public class Foo
{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date)
{
return formatter.get().format(date);
}
}
Puisqu'un ThreadLocal
est une référence aux données d'un Thread
vous pouvez vous retrouver avec des fuites de chargement de classe en utilisant ThreadLocal
dans les serveurs d'application qui utilisent des pools de threads. Vous devez être très attentif au nettoyage de tout ThreadLocal
vous get()
ou set()
en utilisant le ThreadLocal
's remove()
méthode.
Si vous ne procédez pas à un nettoyage lorsque vous avez terminé, toutes les références qu'il contient à des classes chargées dans le cadre d'une application Web déployée resteront dans le dossier de l'utilisateur. amas permanent et ne sera jamais collecté par les ordures. Le redéploiement/déploiement de la webapp ne nettoiera pas chaque fichier Thread
de la référence à la (aux) classe(s) de votre webapp puisque l'option Thread
n'est pas une propriété de votre application web. Chaque déploiement successif créera une nouvelle instance de la classe qui ne sera jamais collectée.
Vous vous retrouverez avec des exceptions de manque de mémoire dues à java.lang.OutOfMemoryError: PermGen space
et après quelques recherches sur le web, je vais probablement augmenter -XX:MaxPermSize
au lieu de corriger le bogue.
Si vous rencontrez ces problèmes, vous pouvez déterminer quel thread et quelle classe conservent ces références en utilisant la commande L'analyseur de mémoire d'Eclipse et/ou en suivant Le guide de Frank Kieviet et suivi de .
Mise à jour : Redécouverte de Article de blog d'Alex Vasseur qui m'a aidé à retrouver ThreadLocal
les problèmes que j'avais.
De nombreux frameworks utilisent les ThreadLocals pour maintenir un certain contexte lié au thread actuel. Par exemple, lorsque la transaction en cours est stockée dans un ThreadLocal, vous n'avez pas besoin de la passer en paramètre à chaque appel de méthode, au cas où quelqu'un en bas de la pile aurait besoin d'y accéder. Les applications Web peuvent stocker des informations sur la requête et la session en cours dans un ThreadLocal, afin que l'application puisse y accéder facilement. Avec Guice, vous pouvez utiliser les ThreadLocals lors de l'implémentation des éléments suivants lunettes de visée personnalisées pour les objets injectés (l'option par défaut de Guice champs d'application des servlets les utilisent probablement aussi).
Les ThreadLocals sont une sorte de variables globales (bien que légèrement moins maléfiques car elles sont limitées à un seul thread), vous devez donc être prudent lorsque vous les utilisez pour éviter les effets secondaires indésirables et les fuites de mémoire. Concevez vos API de manière à ce que les valeurs ThreadLocal soient toujours automatiquement effacées lorsqu'elles ne sont plus nécessaires et qu'une utilisation incorrecte de l'API ne soit pas possible (par exemple comme ceci ). Les ThreadLocals peuvent être utilisés pour rendre le code plus propre, et dans certains cas rares, ils sont la seule façon de faire fonctionner quelque chose (mon projet actuel avait deux cas de ce genre ; ils sont documentés ici sous "Champs statiques et variables globales").
En Java, si vous avez une donnée qui peut varier en fonction du thread, vous avez le choix entre transmettre cette donnée à chaque méthode qui en a (ou pourrait en avoir) besoin, ou associer la donnée au thread. Transmettre la donnée partout peut fonctionner si toutes vos méthodes ont déjà besoin de transmettre une variable "contextuelle" commune.
Si ce n'est pas le cas, vous ne voudrez peut-être pas encombrer vos signatures de méthodes avec un paramètre supplémentaire. Dans un monde non threadé, vous pourriez résoudre le problème avec l'équivalent Java d'une variable globale. Dans un monde threadé, l'équivalent d'une variable globale est une variable thread-local.
Essentiellement, lorsque vous avez besoin d'un la valeur de la variable dépend du fil d'exécution actuel. et il il n'est pas pratique pour vous d'attacher la valeur au fil d'une autre manière (par exemple, la sous-classification de thread).
Un cas typique est celui où un autre cadre a créé le fil que votre code s'exécute, par exemple dans un conteneur de servlets, ou lorsqu'il est simplement plus logique d'utiliser ThreadLocal parce que votre variable est alors "à sa place logique" (plutôt qu'une variable accrochée à une sous-classe Thread ou dans une autre carte de hachage).
Sur mon site web, j'ai d'autres discussion et exemples d'utilisation de ThreadLocal qui peuvent également vous intéresser.
Certaines personnes préconisent l'utilisation de ThreadLocal comme moyen d'attacher un "thread ID" à chaque thread dans certains algorithmes concurrents où vous avez besoin d'un numéro de thread (voir par exemple Herlihy & Shavit). Dans de tels cas, vérifiez que vous en tirez réellement un avantage !
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.