Quand et comment dois-je utiliser une variable ThreadLocal?


Quand dois-je utiliser une variable ThreadLocal?

Comment est-il utilisé?

Author: Andrew Tobilko, 2009-05-03

22 answers

Une utilisation possible (et courante) est lorsque vous avez un objet qui n'est pas thread-safe, mais que vous voulez éviter synchroniserl'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);
    }
}

Documentation.

 786
Author: overthink, 2018-04-25 17:51:39

Étant donné qu'un ThreadLocal est une référence aux données dans un Thread donné, vous pouvez vous retrouver avec des fuites de chargement de classe lors de l'utilisation de ThreadLocals dans des serveurs d'applications qui utilisent des pools de threads. Vous devez faire très attention au nettoyage de tout ThreadLocal s vous get() ou set() en utilisant la méthode ThreadLocal's remove().

Si vous ne nettoyez pas lorsque vous avez terminé, toutes les références qu'il contient aux classes chargées dans le cadre d'une application Web déployée resteront dans le tas permanent et ne seront jamais récupérées. Redéployer / annuler le déploiement de la webapp ne nettoiera pas chaque référence Thread aux classes de votre webapp car le Thread n'est pas quelque chose qui appartient à votre webapp. Chaque déploiement successif créera une nouvelle instance de la classe qui ne sera jamais récupérée.

Vous vous retrouverez avec des exceptions de mémoire en raison de java.lang.OutOfMemoryError: PermGen space et après quelques recherches sur Google, vous augmenterez probablement -XX:MaxPermSize au lieu de corriger le bogue.

Si vous rencontrez ces problèmes, vous pouvez déterminez quel thread et quelle classe conservent ces références en utilisant l'analyseur de mémoire d'Eclipse et/ou en suivant le guide de Frank Kieviet et suivi .

Mise à jour: Re-découvert L'entrée de blog d'Alex Vasseur qui m'a aidé à retrouver certains ThreadLocal problèmes que j'avais.

 381
Author: Phil M, 2012-07-27 22:42:09

De nombreux frameworks utilisent 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 tant que paramètre à travers 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 demande et la session en cours dans un ThreadLocal, afin que l'application y ait un accès facile. Avec Guice, vous pouvez utiliser ThreadLocals lors de l'implémentation de custom scopes pour les objets injectés (les scopes de servlet par défaut de Guice les utilisent probablement aussi).

Les ThreadLocals sont une sorte de variables globales (bien que légèrement moins mauvaises car elles sont limitées à un 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 afin 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). ThreadLocals peut être utilisé pour rendre le code plus propre, et dans de rares cas, ils sont le seul moyen de faire fonctionner quelque chose (mon projet actuel avait deux cas de ce type; ils sont documentés ici sous "Champs statiques et variables globales").

 125
Author: Esko Luontola, 2011-07-14 06:46:54

En Java, si vous avez une donnée qui peut varier par thread, vos choix sont de transmettre cette donnée à chaque méthode qui en a besoin (ou peut en avoir besoin), ou d'associer la donnée au thread. Passer la donnée partout peut être réalisable si toutes vos méthodes ont déjà besoin de passer autour d'une variable "contexte" commune.

Si ce n'est pas le cas, vous ne voudrez peut-être pas encombrer vos signatures de méthode avec un paramètre supplémentaire. Dans un monde non fileté, vous pourriez résoudre le problème avec l'équivalent Java d'une variable globale. Dans un mot fileté, l'équivalent d'une variable globale est une variable thread-local.

 43
Author: user100464, 2009-05-03 20:20:39

Essentiellement, lorsque vous avez besoin de la valeur d'une variablepour dépendre du thread actuel et quene vous convient pas d'attacher la valeur au thread d'une autre manière (par exemple, un thread de sous-classement).

Un cas typique est celui où un autre framework a créé le thread dans lequel votre code s'exécute, par exemple un conteneur de servlet, ou où il est tout simplement plus logique d'utiliser ThreadLocal car votre variable est alors "à sa place logique" (plutôt qu'une variable suspendu à une sous-classe de thread ou dans une autre carte de hachage).

Sur mon site Web, j'ai d'autres discussions et des exemples de quand utiliser ThreadLocal qui peuvent également être intéressants.

Certaines personnes préconisent d'utiliser ThreadLocal comme moyen d'attacher un "ID de thread" à 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 obtenez vraiment un avantage!

 13
Author: Neil Coffey, 2009-05-03 23:50:05

Il y a un très bon exemple dans le livre La concurrence Java dans la pratique. Où l'auteur (Joshua Bloch) explique comment le confinement des threads est l'un des moyens les plus simples d'atteindre la sécurité des threads et ThreadLocal est un moyen plus formel de maintenir le confinement des threads. À la fin il explique également comment les gens peuvent en abuser en l'utilisant comme variables globales.

J'ai copié le texte du livre mentionné mais le code 3.10 est manquant car il n'est pas très important de comprendre où ThreadLocal devrait être utilisé.

Les variables locales de thread sont souvent utilisées pour empêcher le partage dans les plans basés sur des Singletons mutables ou des variables globales. Par exemple, une application à thread unique peut maintenir une connexion de base de données globale qui est initialisée au démarrage pour éviter d'avoir à passer une connexion à chaque méthode. Étant donné que les connexions JDBC peuvent ne pas être thread-safe, une application multithread qui utilise une connexion globale sans coordination supplémentaire n'est pas thread-safe soit. En utilisant un ThreadLocal pour stocker la connexion JDBC, comme dans ConnectionHolder dans la liste 3.10, chaque thread aura sa propre connexion.

ThreadLocal est largement utilisé dans la mise en œuvre de frameworks d'application. Par exemple, les conteneurs J2EE associent un contexte de transaction à un thread en cours d'exécution pendant la durée d'un appel EJB. Ceci est facilement implémenté à l'aide d'un thread statique local contenant le contexte de transaction: lorsque le code du framework doit déterminer quelle transaction est actuellement en cours d'exécution, il récupère le contexte de transaction à partir de ce ThreadLocal. Ceci est pratique en ce sens qu'il réduit le besoin de transmettre des informations de contexte d'exécution dans chaque méthode, mais couple tout code qui utilise ce mécanisme au framework.

Il est facile d'abuser de ThreadLocal en traitant sa propriété thread confinement comme une licence pour utiliser des variables globales ou comme un moyen de créer des arguments de méthode "cachés". Comme les variables globales, variables, peut nuire à réutilisabilité et introduire des accouplements cachés entre les classes, et doit donc être utilisé avec précaution.

 11
Author: Rakesh Chauhan, 2018-03-28 14:28:38

La documentation le dit très bien: "chaque thread qui accède à [une variable locale de thread] (via sa méthode get ou set) a sa propre copie initialisée indépendamment de la variable".

Vous en utilisez un lorsque chaque thread doit avoir sa propre copie de quelque chose. Par défaut, les données sont partagées entre les threads.

 9
Author: RichieHindle, 2014-02-27 13:31:34

Le serveur Webapp peut conserver un pool de threads, et un ThreadLocal var doit être supprimé avant la réponse au client, ainsi le thread actuel peut être réutilisé par la requête suivante.

 9
Author: znlyj, 2016-11-29 11:58:13
  1. ThreadLocal en Java avait été introduit sur JDK 1.2 mais a ensuite été généralisé dans JDK 1.5 pour introduire la sécurité de type sur la variable ThreadLocal.

  2. ThreadLocal peut être associé à la portée du Thread, tout le code exécuté par le Thread a accès aux variables ThreadLocal mais deux threads ne peuvent pas se voir.variable ThreadLocal.

  3. Chaque thread contient une copie exclusive de la variable ThreadLocal qui devient éligible à la récupération de place après thread terminé ou mort, normalement ou en raison d'une exception, Étant donné que ces variables ThreadLocal n'ont pas d'autres références en direct.

  4. Les variables ThreadLocal en Java sont généralement des champs statiques privés dans les classes et conservent leur état à l'intérieur du Thread.

En savoir plus: http://javarevisited.blogspot.com/2012/05/how-to-use-threadlocal-in-java-benefits.html#ixzz2XltgbHTK

 8
Author: Abhijit Gaikwad, 2013-11-13 09:59:38

Deux cas d'utilisation où la variable threadlocal peut être utilisée -
1-Lorsque nous avons une exigence d'associer l'état à un thread (par exemple, un ID utilisateur ou un ID de transaction). Cela se produit généralement avec une application Web que chaque demande allant à un servlet a un transactionID unique qui lui est associé.

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

Notez qu'ici la méthode withInitial est implémentée en utilisant l'expression lambda.
2-Un autre cas d'utilisation est lorsque nous voulons avoir une instance thread safe et que nous ne voulons pas utiliser synchronisation le coût de performances avec la synchronisation est plus. Un tel cas est lorsque SimpleDateFormat est utilisé. Étant donné que SimpleDateFormat n'est pas thread safe, nous devons donc fournir un mécanisme pour le rendre thread safe.

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}
 6
Author: infoj, 2017-01-29 15:21:25

Vous devez être très prudent avec le motif ThreadLocal. Il y a des inconvénients majeurs comme Phil mentionné, mais celui qui n'a pas été mentionné est de s'assurer que le code qui met en place le contexte ThreadLocal n'est pas "rentrant."

De mauvaises choses peuvent se produire lorsque le code qui définit les informations est exécuté une deuxième ou une troisième fois, car les informations de votre thread peuvent commencer à muter lorsque vous ne vous y attendiez pas. Prenez donc soin de vous assurer que les informations ThreadLocal n'ont pas été définies avant de vous le réglez à nouveau.

 4
Author: Jeff Richley, 2012-10-23 18:50:09

Rien de vraiment nouveau ici, mais j'ai découvert aujourd'hui que ThreadLocal est très utile lors de l'utilisation de la validation Bean dans une application Web. Les messages de validation sont localisés, mais utilisent par défaut Locale.getDefault(). Vous pouvez configurer le Validator avec un autre MessageInterpolator, mais il n'y a aucun moyen de spécifier le Locale lorsque vous appelez validate. Vous pouvez donc créer un ThreadLocal<Locale> statique (ou mieux encore, un conteneur général avec d'autres choses dont vous pourriez avoir besoin d'être ThreadLocal, puis demander à votre MessageInterpolator personnalisé de choisir le Locale à partir de cela. La prochaine étape est de écrivez un ServletFilter qui utilise une valeur de session ou request.getLocale() pour choisir les paramètres régionaux et les stocker dans votre référence ThreadLocal.

 3
Author: Colselaw, 2013-01-31 01:37:35

Comme mentionné par @unknown (google), son utilisation est de définir une variable globale dans laquelle la valeur référencée peut être unique dans chaque thread. Ses utilisations impliquent généralement de stocker une sorte d'informations contextuelles liées au thread d'exécution actuel.

Nous l'utilisons dans un environnement Java EE pour transmettre l'identité de l'utilisateur à des classes qui ne sont pas conscientes de Java EE (n'ont pas accès à HttpSession, ou à l'EJB SessionContext). De cette façon, le code, qui utilise l'identité pour les opérations basées sur la sécurité peuvent accéder à l'identité de n'importe où, sans avoir à la transmettre explicitement dans chaque appel de méthode.

Le cycle d'opérations requête/réponse dans la plupart des appels Java EE facilite ce type d'utilisation car il donne des points d'entrée et de sortie bien définis pour définir et désactiver le ThreadLocal.

 3
Author: Robin, 2013-04-27 08:12:53

ThreadLocal assurera l'accès à l'objet mutable par le multiple threads dans la méthode non synchronisée est synchronisé, signifie faire l'objet mutable doit être immuable dans la méthode.

Cette est obtenu en donnant une nouvelle instance d'objet mutable pour chaque thread essayez d'y accéder. Il s'agit donc d'une copie locale dans chaque thread. C'est certains hack sur la création d'une variable d'instance dans une méthode à accéder comme un variable locale. Comme vous le savez la variable locale de la méthode est disponible uniquement pour le thread, une différence est; les variables locales de la méthode ne le seront pas disponible pour le thread une fois l'exécution de la méthode terminée où comme mutable l'objet partagé avec threadlocal sera disponible sur plusieurs méthodes jusqu'à ce que nous le nettoyer.

Par Définition:

La classe ThreadLocal en Java vous permet de créer des variables qui peuvent seulement être lu et écrit par le même fil. Ainsi, même si deux threads exécutent le même code, et le code a une référence à un Variable ThreadLocal, alors les deux threads ne peuvent pas se voir Variables ThreadLocal.

Chaque Thread en java contient ThreadLocalMap dans lui.

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

Réalisation du ThreadLocal:

Créez maintenant une classe wrapper pour ThreadLocal qui va contenir l'objet mutable comme ci-dessous (avec ou sans initialValue()).
Maintenant getter et setter de ce wrapper fonctionneront sur l'instance threadlocal au lieu de objet mutable.

Si getter() de threadlocal n'a trouvé aucune valeur avec dans le threadlocalmap du Thread; alors il appellera initialValue() pour obtenir sa copie privée par rapport au thread.

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

Maintenant wrapper.getDateFormatter() appellera threadlocal.get() et cela vérifiera que le currentThread.threadLocalMapcontient cette instance (threadlocal).
Si oui, retournez la valeur (SimpleDateFormat) pour l'instance threadlocal correspondante
sinon, ajoutez la carte avec cette instance threadlocal, initialValue ().

Ici, la sécurité des threads est atteinte sur cette classe mutable; par chaque thread travaille avec sa propre instance mutable mais avec la même instance ThreadLocal. Signifie que tout le thread partagera la même instance ThreadLocal en tant que clé, mais une instance SimpleDateFormat différente en tant que valeur.

Https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java

 3
Author: Kanagavelu Sugumar, 2016-01-07 05:29:06

Quand?

Lorsqu'un objet n'est pas thread-safe, au lieu de la synchronisation qui entrave l'évolutivité, donnez un objet à chaque thread et conservez-le thread scope, qui est ThreadLocal. L'un des objets les plus utilisés mais non thread-safe sont database Connection et JMSConnection.

Comment ?

Un exemple est Spring framework utilise ThreadLocal fortement pour gérer les transactions dans les coulisses en conservant ces objets de connexion dans les variables ThreadLocal. À haut niveau, lorsqu'une transaction est démarrée, il obtient la connexion ( et désactive la validation automatique ) et la maintient dans ThreadLocal. lors d'autres appels db, il utilise la même connexion pour communiquer avec db. À la fin, il prend la connexion de ThreadLocal et valide ( ou annule ) la transaction et libère la connexion.

Je pense que log4j utilise également ThreadLocal pour maintenir MDC.

 3
Author: Limestone, 2016-04-27 03:10:49

ThreadLocal est utile, lorsque vous voulez avoir un état qui ne devrait pas être partagé entre différents threads, mais il devrait être accessible à partir de chaque thread pendant toute sa durée de vie.

Par exemple, imaginez une application Web, où chaque requête est servie par un thread différent. Imaginez que pour chaque demande, vous avez besoin d'un élément de données plusieurs fois, ce qui est assez coûteux à calculer. Cependant, ces données peuvent avoir changé pour chaque demande entrante, ce qui signifie que vous ne pouvez pas utiliser un simple cache. Une solution simple et rapide à ce problème serait d'avoir une variable ThreadLocal détenant l'accès à ces données, de sorte que vous ne devez le calculer qu'une seule fois pour chaque demande. Bien sûr, ce problème peut également être résolu sans l'utilisation de ThreadLocal, mais je l'ai conçu à des fins d'illustration.

Cela dit, gardez à l'esprit que ThreadLocal s sont essentiellement une forme d'état global. En conséquence, il a de nombreuses autres implications et ne devrait être utilisé qu'après avoir examiné toutes les autres solutions possibles.

 2
Author: Dimos, 2017-09-16 11:28:11

Les variables locales de thread sont souvent utilisées pour empêcher le partage dans les conceptions basées sur singletons mutables ou variables globales.

Il peut être utilisé dans des scénarios tels que la création d'une connexion JDBC séparée pour chaque thread lorsque vous n'utilisez pas de pool de connexions.

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

Lorsque vous appelez getConnection, il renverra une connexion associée à ce thread.La même chose peut être faite avec d'autres propriétés comme dateformat, contexte de transaction que vous ne souhaitez pas partager entre les threads.

Vous auriez également pu utiliser des variables locales pour la même chose, mais ces ressources prennent généralement du temps dans la création,vous ne voulez donc pas les créer encore et encore chaque fois que vous effectuez une logique métier avec elles. Cependant, les valeurs ThreadLocal sont stockées dans l'objet thread lui-même et dès que le thread est collecté, ces valeurs ont également disparu.

Ce lien explique très bien l'utilisation de ThreadLocal.

 2
Author: bpjoshi, 2017-11-30 07:58:44

Depuis la publication de Java 8, il existe un moyen plus déclaratif d'initialiser ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

Jusqu'à la sortie de Java 8, vous deviez effectuer les opérations suivantes:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

De plus, si la méthode d'instanciation (constructeur, méthode factory) de la classe utilisée pour {[3] } ne prend aucun paramètre, vous pouvez simplement utiliser des références de méthode (introduites dans Java 8):

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

Remarque: L'évaluation est paresseuse car vous passez java.util.function.Supplier lambda qui n'est évalué que lorsque ThreadLocal#get est appelé mais value n'a pas été évalué.

 2
Author: Andrii Abramov, 2018-03-28 14:44:39

Mise en cache, parfois vous devez calculer la même valeur beaucoup de temps, donc en stockant le dernier ensemble d'entrées dans une méthode et le résultat, vous pouvez accélérer le code. En utilisant le stockage local de Thread, vous évitez d'avoir à penser au verrouillage.

 0
Author: Ian Ringrose, 2015-06-15 17:19:01

ThreadLocal est une fonctionnalité spécialement provisionnée par JVM pour fournir un espace de stockage isolé uniquement pour les threads. comme la valeur de l'instance d'étendue variable sont liés à une instance d'une classe seulement. chaque objet a ses seules valeurs et ils ne peuvent pas voir la valeur de l'autre. il en va de même pour le concept de variables ThreadLocal, elles sont locales au thread dans le sens des instances d'objet autre thread sauf pour celui qui l'a créé, ne peut pas le voir. Voir Ici

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}
 0
Author: Ajay, 2017-05-30 14:09:57

Threadlocal fournit un moyen très facile d'obtenir la réutilisation des objets avec un coût nul.

J'ai eu une situation où plusieurs threads créaient une image de cache mutable, à chaque notification de mise à jour.

J'ai utilisé un Threadlocal sur chaque fil, puis chaque thread juste besoin de réinitialiser l'ancienne image et ensuite mettre à jour à partir du cache sur chaque notification de mise à jour.

Les objets réutilisables habituels des pools d'objets ont un coût de sécurité des threads qui leur est associé, alors que l'approche n'en a aucun.

 0
Author: Dev Amitabh, 2017-12-12 03:00:41

La classe ThreadLocal en Java vous permet de créer des variables qui ne peuvent être lues et écrites que par le même thread. Ainsi, même si deux threads exécutent le même code et que le code a une référence à une variable ThreadLocal, les deux threads ne peuvent pas voir les variables ThreadLocal de l'autre.

Lire la suite

 0
Author: Pritesh Patel, 2018-06-04 13:18:08