Ich habe hier das JavaDoc für Threadlocal gelesen
http://Java.Sun.com/j2se/1.5.0/docs/api/Java/lang/ThreadLocal.html
und es heißt "". ThreadLocal-Instanzen sind normalerweise private statische Felder in Klassen, die einem Thread einen Zustand zuordnen möchten (z. B. eine Benutzer-ID oder eine Transaktions-ID). "
Aber meine Frage ist, warum sie sich entschieden haben, es statisch zu machen (in der Regel) - es ist etwas verwirrend, wenn der Status "pro Thread" vorhanden ist, aber die Felder sind statisch.
Wenn es sich dabei um ein Instanzebenenfeld handelt, wäre es tatsächlich "Pro Thread - Pro Instanz" und nicht nur ein garantiertes "Pro Thread". Das ist normalerweise nicht die Semantik, nach der Sie suchen.
Normalerweise enthält es Objekte wie Objekte, die auf eine Benutzerunterhaltung, eine Webanforderung usw. ausgerichtet sind. Sie möchten nicht, dass diese Objekte auch auf die Instanz der Klasse beschränkt sind.
Eine Webanfrage => eine Persistenzsitzung.
Keine Webanforderung => eine Persistenzsitzung pro Objekt.
Machen Sie es entweder statisch oder versuchen Sie, statische Felder in Ihrer Klasse zu vermeiden - machen Sie die Klasse selbst zu einem Singleton, und Sie können die ThreadLocal auf Instanzebene sicher verwenden, solange Sie dieses Singleton global verfügbar haben.
Das muss nicht sein. Das Wichtigste ist, dass es ein Singleton sein sollte.
Der Grund ist, dass auf die Variablen über einen Zeiger zugegriffen wird, der dem Thread zugeordnet ist. Sie verhalten sich wie globale Variablen mit Thread-Gültigkeitsbereich, daher ist statisch am besten geeignet. Dies ist die Art und Weise, wie Sie den lokalen Zustand des Threads in Dingen wie pthreads erhalten, sodass dies nur ein Zufall der Geschichte und der Implementierung sein kann.
Beziehen Sie sich auf this , dies gibt ein besseres Verständnis.
Kurz gesagt, ThreadLocal
-Objekt funktioniert wie eine Schlüsselwertzuordnung. Wenn der Thread die Methode ThreadLocal
get/set
aufruft, ruft er das Thread-Objekt im Schlüssel der Map ab und speichert ihn und den Wert im Wert der Map. Aus diesem Grund werden für verschiedene Threads unterschiedliche Werte kopiert (die Sie lokal speichern möchten), da sie sich im Eintrag einer anderen Map befinden.
Deshalb benötigen Sie nur eine Karte, um alle Werte zu erhalten. Obwohl dies nicht unbedingt erforderlich ist, können Sie mehrere Maps (ohne Static deklarieren) haben, um auch jedes Thread-Objekt beizubehalten. Dies ist völlig redundant, weshalb statische Variablen bevorzugt werden.
Eine Verwendung für ein Threadlocal für eine Instanz pro Thread pro Thread ist, wenn Sie möchten, dass etwas in allen Methoden eines Objekts sichtbar ist und es für den Thread sicher ist, ohne dass der Zugriff darauf synchronisiert wird, wie Sie es für ein gewöhnliches Feld tun würden.
static final ThreadLocal
-Variablen sind threadsicher.
static
macht die ThreadLocal-Variable nur für den jeweiligen Thread für mehrere Klassen verfügbar. Hierbei handelt es sich um eine Art globale Variable-Dekaration der jeweiligen lokalen Thread-Variablen für mehrere Klassen.
Wir können diese Thread-Sicherheit mit dem folgenden Codebeispiel überprüfen.
CurrentUser
- speichert die aktuelle Benutzer-ID in ThreadLocalTestService
- Einfacher Dienst mit der Methode - getUser()
, um den aktuellen Benutzer von CurrentUser abzurufen.TestThread
- Diese Klasse wird zum Erstellen mehrerer Threads verwendet und gleichzeitig Benutzer-IDs festgelegt.
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 TestThread-Hauptklasse ..__ aus. Ausgabe -
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
End-main->62->62
End-ForkJoinPool.commonPool-worker-1->87->87
End-ForkJoinPool.commonPool-worker-2->31->31
End-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-2->32->32
Start-ForkJoinPool.commonPool-worker-3->82->82
Start-ForkJoinPool.commonPool-worker-1->88->88
Start-main->63->63
End-ForkJoinPool.commonPool-worker-1->88->88
End-main->63->63
...
Analysezusammenfassung
main
Die Ausführung wird beendet und der aktuelle Benutzer wird als "62" ausgegeben. Parallel dazu wird ForkJoinPool.commonPool-worker-1
die Ausführung beendet und der aktuelle Benutzer wird als "87" ausgegeben. Parallel dazu wird ForkJoinPool.commonPool-worker-2
beendet und der aktuelle Benutzer als "31" ausgegeben. Parallele ForkJoinPool.commonPool-worker-3
der aktuelle Benutzer als "81"Inferenz
Concurrent Threads können korrekte Benutzer-IDs abrufen, auch wenn sie als "static final ThreadLocal" deklariert wurden.