Heim  >  Artikel  >  Java  >  So verwenden Sie die Klasse java.lang.ThreadLocal

So verwenden Sie die Klasse java.lang.ThreadLocal

PHPz
PHPznach vorne
2023-05-05 20:43:13748Durchsuche

1. Übersicht

Was ist ThreadLocal? Tatsächlich ist ThreadLocal keine lokale Implementierungsversion eines Threads, sondern eine threadlokale Variable (lokale Thread-Variable). Vielleicht wäre es passender, es ThreadLocalVar zu nennen. Die eigentliche Funktion lokaler Thread-Variablen (ThreadLocal) ist sehr einfach. Sie stellt eine Kopie des Variablenwerts für jeden Thread bereit, der die Variable verwendet. Es handelt sich um einen speziellen Thread-Bindungsmechanismus in Java, der es jedem Thread ermöglicht, seinen eigenen zu ändern kopieren, ohne dass es zu Konflikten mit den Kopien anderer Threads kommt.

Aus der Sicht eines Threads behält jeder Thread einen impliziten Verweis auf seine Kopie einer Thread-lokalen Variablen bei, solange der Thread aktiv ist und auf die ThreadLocal-Instanz zugegriffen werden kann. Nach dem Verschwinden des Threads sind alle Kopien seiner Thread-lokalen Instanz Garbage Sammlung (sofern es keine anderen Hinweise auf diese Kopien gibt).

Daten, auf die über ThreadLocal zugegriffen wird, beziehen sich immer auf den aktuellen Thread. Mit anderen Worten: Die JVM bindet einen privaten lokalen Instanzzugriffsbereich an jeden laufenden Thread und bietet so eine Lösung für gleichzeitige Zugriffsprobleme, die häufig in Multithread-Umgebungen auftreten .

Wie verwaltet ThreadLocal eine Kopie der Variablen für jeden Thread? Tatsächlich ist die Implementierungsidee sehr einfach. In der ThreadLocal-Klasse gibt es eine Map, die zum Speichern einer Kopie der Variablen jedes Threads verwendet wird.

Zusammenfassend lässt sich sagen, dass der Synchronisationsmechanismus für das Problem der gemeinsamen Nutzung von Multithread-Ressourcen die Methode „Zeit gegen Raum austauschen“ verwendet, während ThreadLocal die Methode „Raum gegen Zeit austauschen“ verwendet. Ersteres stellt nur eine Kopie der Variablen für verschiedene Threads bereit, die für den Zugriff in die Warteschlange gestellt werden, während letzteres eine Kopie der Variablen für jeden Thread bereitstellt, sodass gleichzeitig auf sie zugegriffen werden kann, ohne dass sich dies gegenseitig beeinträchtigt.

2. API-Beschreibung

ThreadLocal()

Erstellen Sie eine lokale Thread-Variable.

T get()

Gibt den Wert in der Kopie dieser Thread-lokalen Variablen des aktuellen Threads zurück, der erstellt und initialisiert wird, wenn der Thread diese Methode zum ersten Mal aufruft.

protected T initialValue()

Gibt den Anfangswert des aktuellen Threads für diese Thread-lokale Variable zurück. Diese Methode wird höchstens einmal pro Thread-Zugriff aufgerufen, um jede Thread-lokale Variable abzurufen, d. h. wenn der Thread zum ersten Mal mit der Methode get() auf die Variable zugreift. Wenn der Thread die set(T)-Methode vor der get-Methode aufruft, wird die initialValue-Methode im Thread nicht erneut aufgerufen.

Wenn diese Implementierung einfach null zurückgibt; wenn der Programmierer threadlokale Variablen mit einem anderen Wert als null initialisieren möchte, muss der Programmierer eine Unterklasse von ThreadLocal erstellen und diese Methode überschreiben. Normalerweise werden anonyme innere Klassen verwendet. Eine typische Implementierung von initialValue ruft eine entsprechende Konstruktormethode auf und gibt das neu erstellte Objekt zurück.

void remove()

Entfernt den Wert dieser Thread-lokalen Variablen. Dies kann dazu beitragen, den Speicherbedarf für Thread-lokale Variablen zu reduzieren. Wenn erneut auf diese Thread-lokale Variable zugegriffen wird, hat sie standardmäßig ihren Anfangswert.

Leerenmenge (T-Wert)

Setzt den Wert in der aktuellen Thread-Kopie dieser Thread-lokalen Variablen auf den angegebenen Wert. Viele Anwendungen benötigen diese Funktionalität nicht und verlassen sich nur auf die Methode initialValue(), um den Wert threadlokaler Variablen festzulegen.

In Programmen wird die Methode initialValue im Allgemeinen überschrieben, um einen bestimmten Anfangswert anzugeben.

3. Typische Beispiele

1. Hiberantes Session-Toolklasse HibernateUtil

Diese Klasse ist die HibernateUtil-Klasse in der offiziellen Dokumentation von Hibernate und wird für die Sitzungsverwaltung verwendet.

öffentliche Klasse HibernateUtil {

privates statisches Protokoll log = LogFactory.getLog(HibernateUtil.class);

private static final SessionFactory sessionFactory; //SessionFactory definieren

statisch {

versuche es mit {

//SessionFactory

über die Standardkonfigurationsdatei hibernate.cfg.xml erstellen sessionFactory = new Configuration().configure().buildSessionFactory();

} Catch (Throwable ex) {

log.error("Initialisierung von SessionFactory fehlgeschlagen!", ex);

wirf einen neuen ExceptionInInitializerError(ex);

}

}

//Erstelle eine lokale Thread-Variablensitzung, um die Sitzung von Hibernate zu speichern

öffentliche statische letzte ThreadLocal-Sitzung = new ThreadLocal();

/**

* Holen Sie sich die Sitzung im aktuellen Thread

* @return Session

* @throws HibernateException

*/

öffentliche statische Sitzung currentSession() löst HibernateException {

aus Session s = (Session) session.get();

// Wenn die Sitzung noch nicht geöffnet ist, öffnen Sie eine neue Sitzung

if (s == null) {

s = sessionFactory.openSession();

session.set(s); //Speichern Sie die neu geöffnete Sitzung in lokalen Thread-Variablen

}

zurück s;

}

public static void closeSession() wirft HibernateException {

//Lokale Thread-Variablen abrufen und in Sitzungstyp umwandeln

Session s = (Session) session.get();

session.set(null);

if (s != null)

s.close();

}

}

Da in dieser Klasse die Methode initialValue() von ThreadLocal nicht überschrieben wird, wird die Thread-Lokalvariablensitzung zum ersten Mal erstellt und ihr Anfangswert ist null. Wenn currentSession() zum ersten Mal aufgerufen wird, wird die Methode get() verwendet der lokalen Thread-Variable ist ebenfalls null . Wenn die Sitzung null ist, wird eine neue Sitzung geöffnet und in der lokalen Thread-Variablensitzung gespeichert. Dies ist auch das von „public static final ThreadLocal session = new ThreadLocal()“ erstellte Objekt. „Der Grund, warum eine Sitzung in ein Hibernate-Sitzungsobjekt umgewandelt werden kann.

2. Ein weiteres Beispiel

Erstellen Sie eine Bean und legen Sie die Bean-Eigenschaften über verschiedene Thread-Objekte fest, um die Unabhängigkeit jedes Thread-Bean-Objekts sicherzustellen.

/**

* Erstellt von IntelliJ IDEA.

* Benutzer: leizhimin

* Datum: 23.11.2007

* Zeit: 10:45:02

* 学生

*/

öffentliche Klasse Student {

private int age = 0; //age

public int getAge() {

gib dieses Alter zurück;

}

public void setAge(int age) {

this.age = Alter;

}

}

/**

* Erstellt von IntelliJ IDEA.

* Benutzer: leizhimin

* Datum: 23.11.2007

* Uhrzeit: 10:53:33

* Testprogramm unter Multithreading

*/

Die öffentliche Klasse ThreadLocalDemo implementiert Runnable {

//Erstellen Sie die lokale Thread-Variable studentLocal, die Sie später finden, um das Student-Objekt zu speichern

private final static ThreadLocal studentLocal = new ThreadLocal();

public static void main(String[] agrs) {

ThreadLocalDemo td = new ThreadLocalDemo();

Thread t1 = neuer Thread(td, "a");

Thread t2 = neuer Thread(td, "b");

t1.start();

t2.start();

}

public void run() {

accessStudent();

}

/**

* Beispiel einer Geschäftsmethode zum Testen

*/

public void accessStudent() {

//Den Namen des aktuellen Threads abrufen

String currentThreadName = Thread.currentThread().getName();

System.out.println(currentThreadName + „ läuft!“);

//Erzeuge eine Zufallszahl und drucke

Zufälliger Zufall = neuer Zufall();

int age = random.nextInt(100);

System.out.println("thread " + currentThreadName + " set age to:" + age);

//Holen Sie sich ein Student-Objekt und fügen Sie das zufällige Alter in die Objekteigenschaften ein

Student student = getStudent();

student.setAge(age);

System.out.println("thread " + currentThreadName + " Alter des ersten Lesens ist:" + student.getAge());

versuche es mit {

Thread.sleep(500);

}

Catch (InterruptedException ex) {

ex.printStackTrace();

}

System.out.println("thread " + currentThreadName + " zweites Lesealter ist:" + student.getAge());

}

protected Student getStudent() {

//Lokale Thread-Variablen abrufen und in den Student-Typ umwandeln

Student student = (Student) studentLocal.get();

//Wenn der Thread diese Methode zum ersten Mal ausführt, muss studentLocal.get() null sein

if (student == null) {

//Erstelle ein Student-Objekt und speichere es in der lokalen Thread-Variable studentLocal

student = neuer Student();

studentLocal.set(student);

}

Rückkehrerschüler;

}

}

Laufergebnis:

a läuft!

Thread ein festgelegtes Alter auf:76

b läuft!

Thread B hat das Alter auf:27

gesetzt Das Mindestalter für das erste Lesen des Threads beträgt:76

Das Mindestalter für das erste Lesen von Thread B beträgt:27

Thread ein zweites Lesealter ist:76

Das zweite Lesealter von Thread B beträgt:27

Es ist ersichtlich, dass die von den beiden Threads gedruckten Werte zu unterschiedlichen Zeiten genau gleich sind. Dieses Programm verwendet ThreadLocal, um Multithread-Parallelität zu erreichen und gleichzeitig die Datensicherheit zu berücksichtigen.

4. Zusammenfassung

ThreadLocal wird hauptsächlich verwendet, um das Problem der Dateninkonsistenz aufgrund der Parallelität in Multithreads zu lösen. ThreadLocal stellt für jeden Thread eine Kopie der Daten bereit, auf die gleichzeitig zugegriffen wird, und führt das Geschäft durch Zugriff auf die Kopie aus. Dies verbraucht Speicher, reduziert den durch die Thread-Synchronisierung verursachten Leistungsverbrauch und verringert auch die Komplexität der Thread-Parallelitätskontrolle.

ThreadLocal kann keine atomaren Typen verwenden, sondern nur Objekttypen. Die Verwendung von ThreadLocal ist viel einfacher als die von synchronisiert.

Sowohl ThreadLocal als auch Synchonized werden verwendet, um den gleichzeitigen Multithread-Zugriff zu lösen. Es gibt jedoch einen wesentlichen Unterschied zwischen ThreadLocal und synchronisiert. Synchronized verwendet einen Sperrmechanismus, sodass jeweils nur ein Thread auf eine Variable oder einen Codeblock zugreifen kann. ThreadLocal stellt für jeden Thread eine Kopie der Variablen bereit, sodass nicht jeder Thread zu einem bestimmten Zeitpunkt auf dasselbe Objekt zugreift, wodurch die Datenfreigabe durch mehrere Threads isoliert wird. Synchronisiert ist genau das Gegenteil. Es wird verwendet, um bei der Kommunikation zwischen mehreren Threads einen Datenaustausch zu ermöglichen.

Synchronized wird für den Datenaustausch zwischen Threads verwendet, während ThreadLocal für die Datenisolation zwischen Threads verwendet wird.

Natürlich kann ThreadLocal synchronisierte nicht ersetzen, sie befassen sich mit unterschiedlichen Problemdomänen. Synchronized wird zur Implementierung des Synchronisationsmechanismus verwendet und ist komplexer als ThreadLocal.

5. Allgemeine Schritte zur Verwendung von ThreadLocal

1. Erstellen Sie in einer Multithread-Klasse (z. B. der ThreadDemo-Klasse) ein ThreadLocal-Objekt threadXxx, um das Objekt xxx zu speichern, das zwischen Threads isoliert werden muss.

2. Erstellen Sie in der ThreadDemo-Klasse eine Methode getXxx(), um die Daten abzurufen, auf die isoliert zugegriffen werden soll. Beurteilen Sie in der Methode, dass Sie ein Objekt des Isolationszugriffstyps new() erzwingen sollten, wenn das ThreadLocal-Objekt null ist anzuwendenden Typ.

3. Rufen Sie in der run()-Methode der ThreadDemo-Klasse die zu bedienenden Daten über die getXxx()-Methode ab. Dadurch wird sichergestellt, dass jeder Thread einem Datenobjekt entspricht und dieses Objekt jederzeit bearbeitet wird.

Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Klasse java.lang.ThreadLocal. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen