und es heißt: “ThreadLocal-Instanzen sind normalerweise private statische Felder in Klassen, die den Status mit einem Thread (z. B. einer Benutzer-ID oder Transaktions-ID) verknüpfen möchten.”
Aber meine Frage ist, warum sie sich dafür entschieden haben, es (normalerweise) statisch zu machen – es macht die Dinge ein bisschen verwirrend, den Status “pro Thread” zu haben, aber die Felder sind statisch?
Denn wenn es sich um ein Feld auf Instanzebene handeln würde, wäre es tatsächlich „Pro Thread – Per Instance“, nicht nur ein garantiertes „Pro Thread“. Das ist normalerweise nicht die Semantik, nach der Sie suchen.
Normalerweise enthält es so etwas wie Objekte, die auf eine Benutzerkonversation, eine Webanforderung usw. beschränkt sind. Sie möchten nicht, dass sie auch auf die Instanz der Klasse beschränkt sind.
Eine Webanforderung => eine Persistenzsitzung.
Nicht eine Webanforderung => eine Persistenzsitzung pro Objekt.
Ich mag diese Erklärung, weil sie zeigt, wie ThreadLocal verwendet werden soll
– kellyfj
8. Mai 2010 um 12:20 Uhr
Pro-Thread-pro-Instanz kann eine nützliche Semantik sein, aber die meisten Anwendungen für dieses Muster würden so viele Objekte beinhalten, dass es besser wäre, a zu verwenden ThreadLocal um einen Verweis auf ein Hash-Set zu halten, das Objekte Thread-Instanzen zuordnet.
– Superkatze
17. März 2014 um 23:03 Uhr
@optional Es bedeutet nur jede Instanz des nicht statischen ThreadLocal würde seine eigenen Thread-lokalen Daten enthalten, selbst wenn diese ThreadLocal Instanzen existieren im selben Thread. Es ist nicht unbedingt falsch, das zu tun – ich nehme an, es könnte nur das am wenigsten beliebte Muster der beiden sein
– geg
6. Januar 2018 um 2:22 Uhr
Machen Sie es entweder statisch oder wenn Sie versuchen, statische Felder in Ihrer Klasse zu vermeiden – machen Sie die Klasse selbst zu einem Singleton, und dann können Sie ThreadLocal auf Instanzebene sicher verwenden, solange Sie dieses Singleton global verfügbar haben.
Es muss nicht sein. Wichtig ist, dass es ein Singleton sein sollte.
Der Grund dafür ist, dass auf die Variablen über einen dem Thread zugeordneten Zeiger zugegriffen wird. Sie verhalten sich wie globale Variablen mit Thread-Gültigkeitsbereich, daher passt statisch am besten. Auf diese Weise erhalten Sie den lokalen Status des Threads in Dingen wie pthreads, sodass dies möglicherweise nur ein Zufall der Geschichte und Implementierung ist.
Beziehen Sie sich darauf, dies gibt ein besseres Verständnis.
Zusamenfassend, ThreadLocal Objekt funktionieren wie eine Schlüssel-Wert-Karte. Wenn der Thread aufgerufen wird ThreadLocalget/set -Methode wird das Thread-Objekt im Schlüssel der Karte und der Wert im Wert der Karte abgerufen/gespeichert. Aus diesem Grund haben verschiedene Threads unterschiedliche Wertkopien (die Sie lokal speichern möchten), da sie sich in verschiedenen Zuordnungseinträgen befinden.
Deshalb benötigen Sie nur eine Karte, um alle Werte zu halten. Obwohl dies nicht erforderlich ist, können Sie mehrere Maps haben (ohne statisch zu deklarieren), um auch jedes Thread-Objekt zu behalten, was völlig redundant ist, weshalb statische Variablen bevorzugt werden.
Chris Mawata
Eine Verwendung für ein threadlocal auf einer pro Instanz pro Thread ist, wenn Sie möchten, dass etwas in allen Methoden eines Objekts sichtbar ist und es Thread-sicher ist, ohne den Zugriff darauf zu synchronisieren, wie Sie es für ein gewöhnliches Feld tun würden.
static final ThreadLocal Variablen sind threadsicher.
static macht die ThreadLocal-Variable über mehrere Klassen hinweg nur für den jeweiligen Thread verfügbar. es ist eine Art globale Variablendekartierung der jeweiligen Thread-Lokalvariablen über mehrere Klassen hinweg.
Wir können die Sicherheit dieses Threads mit dem folgenden Codebeispiel überprüfen.
CurrentUser – speichert die aktuelle Benutzer-ID in ThreadLocal
TestService – Einfacher Service mit Methode – getUser() um den aktuellen Benutzer aus CurrentUser abzurufen.
TestThread – Diese Klasse wird zum Erstellen mehrerer Threads und zum gleichzeitigen Festlegen von Benutzer-IDs verwendet
.
public class CurrentUser
public class CurrentUser {
private static final ThreadLocal<String> CURRENT = new ThreadLocal<String>();
public static ThreadLocal<String> getCurrent() {
return CURRENT;
}
public static void setCurrent(String user) {
CURRENT.set(user);
}
}
public class TestService {
public String getUser() {
return CurrentUser.getCurrent().get();
}
}
.
import java.util.ArrayList;
import java.util.List;
public class TestThread {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
//creates a List of 100 integers
for (int i = 0; i < 100; i++) {
integerList.add(i);
}
//parallel stream to test concurrent thread execution
integerList.parallelStream().forEach(intValue -> {
//All concurrent thread will set the user as "intValue"
CurrentUser.setCurrent("" + intValue);
//Thread creates a sample instance for TestService class
TestService testService = new TestService();
//Print the respective thread name along with "intValue" value and current user.
System.out.println("Start-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
try {
//all concurrent thread will wait for 3 seconds
Thread.sleep(3000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Print the respective thread name along with "intValue" value and current user.
System.out.println("End-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
});
}
}
.
Führen Sie die Hauptklasse TestThread aus. Ausgabe –
“main”-Thread startet und setzt den aktuellen Benutzer auf “62”, parallel startet der “ForkJoinPool.commonPool-worker-2”-Thread und setzt den aktuellen Benutzer auf “31”, parallel startet der “ForkJoinPool.commonPool-worker-3”-Thread und setzt den aktuellen Benutzer als „81“, parallel startet der Thread „ForkJoinPool.commonPool-worker-1“ und setze den aktuellen Benutzer als „87“ Start-main->62->62 Start-ForkJoinPool.commonPool-worker-2->31->31 Start-ForkJoinPool.commonPool-worker-3->81->81 Start-ForkJoinPool.commonPool-worker-1->87->87
Alle diese oben genannten Threads werden für 3 Sekunden schlafen
main Ausführung beendet und parallel den aktuellen Benutzer als “62” ausgeben ForkJoinPool.commonPool-worker-1 Ausführung beendet und parallel den aktuellen Benutzer als “87” ausgeben ForkJoinPool.commonPool-worker-2 Ausführung beendet und parallel den aktuellen Benutzer als “31” ausgeben ForkJoinPool.commonPool-worker-3 Ausführung beendet und den aktuellen Benutzer als “81” ausgeben
Inferenz
Gleichzeitige Threads sind in der Lage, korrekte Benutzer-IDs abzurufen, auch wenn sie als “statisch final ThreadLocal” deklariert wurden.