Wie im Bild gezeigt:
# 🎜🎜#SchnellstartAls Nächstes zeigen wir Ihnen anhand eines einfachen Beispiels die grundlegende Verwendung von ThreadLocal
package cuit.pymjl.thradlocal; /** * @author Pymjl * @version 1.0 * @date 2022/7/1 10:56 **/ public class MainTest { static ThreadLocal<String> threadLocal = new ThreadLocal<>(); static void print(String str) { //打印当前线程中本地内存中本地变量的值 System.out.println(str + " :" + threadLocal.get()); //清除本地内存中的本地变量 threadLocal.remove(); } public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { //设置线程1中本地变量的值 threadLocal.set("thread1 local variable"); //调用打印方法 print("thread1"); //打印本地变量 System.out.println("after remove : " + threadLocal.get()); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { //设置线程1中本地变量的值 threadLocal.set("thread2 local variable"); //调用打印方法 print("thread2"); //打印本地变量 System.out.println("after remove : " + threadLocal.get()); } }); t1.start(); t2.start(); } }
Das Prinzip von ThreadLocal
# 🎜🎜# Wie aus dieser Abbildung ersichtlich ist, gibt es in der Thread-Klasse ein threadLocals und ein inheritableThreadLocals. Beide sind Variablen vom Typ ThreadLocalMap, und ThreadLocalMap ist eine benutzerdefinierte Hashmap. Standardmäßig sind diese beiden Variablen in jedem Thread null und werden nur erstellt, wenn der aktuelle Thread die Set- oder Get-Methode von ThreadLocal zum ersten Mal aufruft. Tatsächlich werden die lokalen Variablen jedes Threads nicht in der ThreadLocal-Instanz gespeichert, sondern in der threadLocals-Variablen des aufrufenden Threads. Mit anderen Worten, lokale Variablen vom Typ ThreadLocal werden in einem bestimmten Thread-Speicherbereich gespeichert. ThreadLocal ist eine Tool-Shell, die den Wert über die Set-Methode in die ThreadLocals des aufrufenden Threads einfügt und speichert. Wenn der aufrufende Thread seine Get-Methode aufruft, entnimmt er ihn zur Verwendung aus der ThreadLocals-Variablen des aktuellen Threads. Wenn der aufrufende Thread nie beendet wird, wird diese lokale Variable immer in der Variablen threadLocals des aufrufenden Threads gespeichert. Wenn die lokale Variable nicht benötigt wird, können Sie die lokale Variable daher aus den threadLocals des aktuellen Threads löschen Remove-Methode der ThreadLocal-Variablen. Warum sind die ThreadLocals in Thread außerdem als Kartenstruktur konzipiert? Offensichtlich, weil jeder Thread mehreren ThreadLocal-Variablen zugeordnet werden kann. Schauen wir uns als Nächstes den Quellcode von ThreadLocals Set, Get und Remove an code>setInitialValues Code
public void set(T value) { // 1.获取当前线程(调用者线程) Thread t = Thread.currentThread(); // 2.以当前线程作为key值,去查找对应的线程变量,找到对应的map ThreadLocalMap map = getMap(t); if (map != null) { // 3.如果map不为null,则直接添加元素 map.set(this, value); } else { // 4.否则就先创建map,再添加元素 createMap(t, value); } }
TerminatingThreadLocal
. Diese Klasse ist neu in JDK11 und existiert nicht in JDK8, daher gibt es in vielen Quellcode-Analysen im Internet keine relevante Beschreibung dieser Klasse. Ich habe mir den Quellcode dieser Klasse angesehen und ihre Funktion sollte darin bestehen, das Problem von ThreadLocal-Speicherlecks zu vermeiden (bei Interesse können Sie den Quellcode überprüfen und mich bei Fehlern bitte korrigieren). Dies ist die offizielle Erklärung: void createMap(Thread t, T firstValue) { /** * 这里是创建一个ThreadLocalMap,以当前调用线程的实例对象为key,初始值为value * 然后放入当前线程的Therad.threadLocals属性里面 */ t.threadLocals = new ThreadLocalMap(this, firstValue); }
remove
ThreadLocalMap getMap(Thread t) { //这里就是直接获取调用线程的成员属性threadlocals return t.threadLocals; }
ThreadLokaler SpeicherverlustsetInitialValue
的代码
public T get() { // 1.获取当前线程 Thread t = Thread.currentThread(); // 2.获取当前线程的threadlocals,即ThreadLocalMap ThreadLocalMap map = getMap(t); // 3.如果map不为null,则直接返回对应的值 if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } // 4.否则,则进行初始化 return setInitialValue(); }
这里我需要补充说明一下TerminatingThreadLocal
Tatsächlich wurde diese Situation beim Entwurf von ThreadLocalMap berücksichtigt und einige Schutzmaßnahmen hinzugefügt: Alle Schlüssel im Thread ThreadLocalMap werden beim Abrufen (), Set () und Entfernen () gelöscht. von ThreadLocal sind Nullwerte. Diese passiven vorbeugenden Maßnahmen garantieren jedoch nicht, dass es keine Speicherlecks gibt:
Die Zuweisung mit ThreadLocal und das Nichtaufrufen der Methoden get(), set(), remove() führt zu Speicherlecks#🎜 🎜#Warum schwache Referenzen verwenden?
Wenn Sie starke Referenzen verwenden: Wir wissen, dass der Lebenszyklus von ThreadLocalMap im Grunde derselbe ist wie der Lebenszyklus von Thread. Wenn der aktuelle Thread nicht beendet wird, wird ThreadLocalMap niemals von GC recycelt und ThreadLocalMap hat einen starken Wert Verweis auf ThreadLocal, dann ThreadLocal Es wird nicht recycelt. Wenn der Thread-Lebenszyklus lang ist und nicht manuell gelöscht wird, führt dies zu einer KV-Akkumulation, was zu OOM führt. Wenn Sie schwache Referenzen verwenden: Objekte in schwachen Referenzen Sie haben einen kurzen Deklarationszeitraum, da im System während der GC das Objekt recycelt wird, solange eine schwache Referenz gefunden wird, unabhängig davon, ob genügend Heap-Speicherplatz vorhanden ist. Wenn die starke Referenz von ThreadLocal recycelt wird, wird auch die schwache Referenz von ThreadLocalMap recycelt. Wenn kv nicht manuell gelöscht wird, führt dies zu einer Wertakkumulation und führt auch zu OOM
Im Vergleich dazu Durch die Verwendung schwacher Referenzen kann zumindest garantiert werden, dass OOM nicht durch die Anhäufung von Kartenschlüsseln verursacht wird und der entsprechende Wert beim nächsten Aufruf über die Methoden „remove“, „get“ und „set“ gelöscht werden kann. Es ist ersichtlich, dass die Hauptursache für Speicherverluste nicht in schwachen Referenzen liegt, sondern dass der Lebenszyklus von ThreadLocalMap genauso lang ist wie der von Thread, was zu einer Anhäufung von Werten führt Wenn ein OOM verursacht wird, können wir das richtige Medikament verschreiben und sicherstellen, dass es nach jedem Gebrauch verwendet wird. Rufen Sie einfach die
-Methode von ThreadLocal auf, um es zu bereinigen.Das obige ist der detaillierte Inhalt vonSo verwenden Sie die Java ThreadLocal-Klasse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!