webentwicklung-frage-antwort-db.com.de

Warum sollten Java ThreadLocal-Variablen statisch sein?

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.

94
kellyfj

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.

111
Affe

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.

14
Adnan Memon

Das muss nicht sein. Das Wichtigste ist, dass es ein Singleton sein sollte.

10
irreputable

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.

3
Ukko

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 ThreadLocalget/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.

0
GMsoF

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. 

0
Chris Mawata

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 ThreadLocal
  • TestService - 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 

  1. "main" Thread startet und setzt aktuellen Benutzer als "62", parallel "ForkJoinPool.commonPool-worker-2" Thread startet und setzt aktuellen Benutzer als "31", parallel "ForkJoinPool.commonPool-worker-3" Thread startet und setzt den aktuellen Benutzer als "81", parallel "ForkJoinPool.commonPool-worker-1" -Thread wird gestartet und der aktuelle Benutzer wird auf "87" gesetzt 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
  2. Alle diese Threads schlafen 3 Sekunden lang
  3. 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.

0
shijin raj