Frage Wann und wie soll ich eine ThreadLocal-Variable verwenden?


Wann sollte ich ein ThreadLocal Variable?

Wie wird es benutzt?


780
2018-05-03 19:59


Ursprung


Antworten:


Eine mögliche (und gebräuchliche) Verwendung ist, wenn Sie ein Objekt haben, das nicht threadsicher ist, das Sie aber vermeiden möchten synchronisieren Zugang zu diesem Objekt (Ich schaue dich an, SimpleDateFormat). Geben Sie stattdessen jedem Thread eine eigene Instanz des Objekts.

Beispielsweise:

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

Dokumentation.


777
2018-05-03 20:26



Seit einem ThreadLocal ist ein Verweis auf Daten innerhalb eines gegebenen Thread, können Sie am Ende mit ClassLoading Lecks bei der Verwendung enden ThreadLocals in Anwendungsservern, die Thread-Pools verwenden. Sie müssen sehr vorsichtig sein, um irgendwelche zu bereinigen ThreadLocals du get() oder set() mit dem ThreadLocalist es remove() Methode.

Wenn Sie nach Abschluss des Vorgangs nicht aufräumen, bleiben alle Referenzen, die für Klassen gelten, die als Teil einer bereitgestellten Webanwendung geladen wurden, in der permanenter Haufen und wird nie Müll gesammelt bekommen. Das erneute Bereitstellen / Deinstallieren der Webanwendung bereinigt nicht alle Thread's Verweis auf die Klasse (n) Ihrer Webanwendung seit dem Thread gehört nicht zu Ihrer Webanwendung. Bei jeder nachfolgenden Bereitstellung wird eine neue Instanz der Klasse erstellt, die niemals als Garbage Collected erfasst wird.

Sie werden aufgrund von java.lang.OutOfMemoryError: PermGen space und nach etwas googeln wird wahrscheinlich nur noch zunehmen -XX:MaxPermSize anstatt den Fehler zu beheben.

Wenn diese Probleme auftreten, können Sie mithilfe von bestimmen, welcher Thread und welche Klasse diese Referenzen beibehalten Eclipse Speicheranalysator und / oder durch Folgen Frank Kieviets Führer und nachverfolgen.

Update: Wieder entdeckt Alex Vasseurs Blogeintrag das hat mir geholfen, einige aufzuspüren ThreadLocal Probleme, die ich hatte.


380
2018-05-03 22:02



Viele Frameworks verwenden ThreadLocals, um einen Kontext zu dem aktuellen Thread zu verwalten. Wenn die aktuelle Transaktion beispielsweise in einem ThreadLocal gespeichert ist, muss sie nicht als Parameter bei jedem Methodenaufruf übergeben werden, falls jemand im Stapel den Zugriff darauf benötigt. Webanwendungen können Informationen über die aktuelle Anforderung und Sitzung in einem ThreadLocal speichern, sodass die Anwendung problemlos darauf zugreifen kann. Mit Guice können Sie ThreadLocals bei der Implementierung verwenden benutzerdefinierte Bereiche für die injizierten Objekte (Guices Standard Servlet-Bereiche höchstwahrscheinlich auch verwenden).

ThreadLocals sind eine Art von globalen Variablen (obwohl sie etwas weniger bösartig sind, weil sie auf einen Thread beschränkt sind). Daher sollten Sie vorsichtig sein, wenn Sie sie verwenden, um unerwünschte Nebenwirkungen und Speicherlecks zu vermeiden. Entwerfen Sie Ihre APIs so, dass die ThreadLocal-Werte immer automatisch gelöscht werden, wenn sie nicht mehr benötigt werden und eine falsche Verwendung der API nicht möglich ist (z. B. so was). ThreadLocals kann verwendet werden, um den Code sauberer zu machen, und in einigen seltenen Fällen sind sie die einzige Möglichkeit, etwas zum Laufen zu bringen (mein aktuelles Projekt hatte zwei solcher Fälle; sie sind dokumentiert) Hier unter "Statische Felder und Globale Variablen").


123
2018-05-04 13:36



Wenn Sie in Java ein Datum haben, das pro Thread variieren kann, müssen Sie dieses Datum an jede Methode übergeben, die es benötigt (oder benötigen könnte), oder das Datum dem Thread zuordnen. Das Übergeben des Datums überall kann funktionieren, wenn alle Ihre Methoden bereits eine gemeinsame "Kontext" -Variable passieren müssen.

Wenn dies nicht der Fall ist, möchten Sie möglicherweise Ihre Methodensignaturen nicht mit einem zusätzlichen Parameter überladen. In einer Welt ohne Threads könnten Sie das Problem mit dem Java-Äquivalent einer globalen Variablen lösen. In einem Thread-Wort ist das Äquivalent einer globalen Variablen eine Thread-lokale Variable.


42
2018-05-03 20:20



Im Wesentlichen, wenn Sie eine benötigen Der Wert der Variablen hängt vom aktuellen Thread ab und es Es ist nicht bequem, den Wert auf andere Weise an den Thread anzuhängen (zum Beispiel Unterklassen Thread).

Ein typischer Fall ist, wo Ein anderes Framework hat den Thread erstellt dass Ihr Code ausgeführt wird, z. ein Servlet-Container, oder wo es nur sinnvoller ist, ThreadLocal zu verwenden, weil Ihre Variable dann "an ihrem logischen Ort" ist (anstatt einer Variablen, die von einer Thread-Unterklasse oder in einer anderen Hash-Map hängt).

Auf meiner Website habe ich noch etwas weiter Diskussion und Beispiele für die Verwendung von ThreadLocal das könnte auch von Interesse sein.

Einige Leute befürworten die Verwendung von ThreadLocal als eine Möglichkeit zum Anhängen einer "Thread-ID" an jeden Thread in bestimmten gleichzeitigen Algorithmen, wo Sie eine Thread-Nummer benötigen (siehe z. B. Herlihy & Shavit). Überprüfen Sie in solchen Fällen, ob Sie wirklich einen Vorteil erhalten!


13
2018-05-03 23:50



Es gibt sehr gutes Beispiel im Buch Java Concurrency in der Praxis. Wo Autor (Joshua Bloch) erklärt, wie Fadeneinschluss eine der einfachsten Möglichkeiten ist, um Fadensicherheit zu erreichen und ThreadLokal ist formeller Mittel zur Aufrechterhaltung der Fadeneinschränkung. Am Ende erklärt er auch, wie Menschen ihn als globale Variable missbrauchen können.

Ich habe den Text aus dem erwähnten Buch kopiert, aber Code 3.10 fehlt, da es nicht wichtig ist zu verstehen, wo ThreadLocal verwendet werden sollte.

Thread-lokale Variablen werden häufig verwendet, um zu verhindern, dass Designs auf Basis von veränderbaren Singletons oder globalen Variablen geteilt werden. Beispiel: Eine Anwendung mit nur einem Thread verwaltet möglicherweise eine globale Datenbankverbindung, die beim Start initialisiert wird, um zu vermeiden, dass eine Verbindung an jede Methode übergeben werden muss. Da JDBC-Verbindungen möglicherweise nicht threadsicher sind, ist eine Multithread-Anwendung, die eine globale Verbindung ohne zusätzliche Koordination verwendet, ebenfalls nicht threadsicher. Wenn Sie wie in ConnectionHolder in Listing 3.10 ein ThreadLocal zum Speichern der JDBC-Verbindung verwenden, hat jeder Thread seine eigene Verbindung.

ThreadLocal wird häufig zur Implementierung von Anwendungs-Frameworks verwendet. Beispielsweise ordnen J2EE-Container einem Transaktionskontext für die Dauer eines EJB-Aufrufs einen ausführenden Thread zu. Dies lässt sich leicht mithilfe eines statischen Thread-Locals implementieren, der den Transaktionskontext enthält: Wenn der Framework-Code ermitteln muss, welche Transaktion gerade ausgeführt wird, ruft er den Transaktionskontext von diesem ThreadLocal ab. Dies ist insofern praktisch, als es die Notwendigkeit verringert, Ausführungskontextinformationen in jede Methode zu übertragen, aber jeden Code, der diesen Mechanismus verwendet, mit dem Framework koppelt.

Es ist leicht, ThreadLocal zu mißbrauchen, indem man seine Thread-Confinement-Eigenschaft als eine Lizenz behandelt, um globale Variablen zu verwenden, oder um "versteckte" Methodenargumente zu erzeugen. Wie globale Variablen können Thread-lokale Variablen die Wiederverwendbarkeit beeinträchtigen und versteckte Kopplungen zwischen Klassen einführen und sollten daher mit Vorsicht verwendet werden.


11
2017-10-04 09:28



Die Dokumentation sagt es sehr gut: "Jeder Thread, der auf [eine Thread-lokale Variable] zugreift (über seine Methode get oder set) hat seine eigene, unabhängig initialisierte Kopie der Variablen".

Sie verwenden einen, wenn jeder Thread eine eigene Kopie von etwas haben muss. Standardmäßig werden Daten zwischen Threads geteilt.


9
2018-05-03 20:05



Der Webapp-Server behält möglicherweise einen Threadpool und a ThreadLocal var sollte vor der Antwort an den Client entfernt werden, daher kann der aktuelle Thread bei der nächsten Anfrage wiederverwendet werden.


9
2018-04-28 15:22



  1. ThreadLocal in Java wurde in JDK 1.2 eingeführt, wurde aber später in JDK 1.5 generalisiert, um die Typsicherheit der ThreadLocal-Variablen zu verbessern.

  2. ThreadLocal kann dem Thread-Bereich zugeordnet werden, der gesamte Code, der von Thread ausgeführt wird, hat Zugriff auf ThreadLocal-Variablen, aber zwei Threads können die ThreadLocal-Variablen der anderen nicht sehen.

  3. Jeder Thread enthält eine exklusive Kopie der ThreadLocal -Variable, die für die Garbage-Sammlung geeignet ist, nachdem der Thread beendet oder gestorben ist, normalerweise oder aufgrund einer Ausnahme. Diese ThreadLocal-Variable hat keine anderen Live-Referenzen.

  4. ThreadLocal-Variablen in Java sind in der Regel private statische Felder in Klassen und behalten ihren Status innerhalb von Thread bei.

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


8
2017-07-01 06:10



Zwei Anwendungsfälle, in denen threadlokale Variablen verwendet werden können -
1- Wenn wir einen Zustand mit einem Thread assoziieren müssen (z. B. eine Benutzer-ID oder Transaktions-ID). Das passiert normalerweise bei einer Webanwendung, bei der jeder Anfrage, die an ein Servlet geht, eine eindeutige transactionID zugeordnet ist.

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

Beachten Sie, dass hier die Methode withInitial mit Lambda-Ausdruck implementiert wird.
2- Ein weiterer Anwendungsfall ist, wenn wir eine threadsichere Instanz haben wollen und wir keine Synchronisation verwenden wollen, da die Leistungskosten bei der Synchronisation mehr sind. Ein solcher Fall ist, wenn SimpleDateFormat verwendet wird. Da SimpleDateFormat nicht threadsicher ist, müssen wir Mechanismen bereitstellen, um es threadsicher zu machen.

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
2017-08-20 15:58