Was ist der Grund, warum ThreadLocal Speicher-OOM verursacht?
Die unterste Ebene von ThreadLocal speichert Daten über ThreadLocalMap
Der Quellcode lautet wie folgt:
Wenn wir ThreadLocal.set() verwenden, werden der Wert und der Schlüssel des Satzes (d. h. Die vom Unternehmen selbst definierte ThreadLocal-Klasse wird im
-Quellcode im Array Entry[] von ThreadLocalMap wie folgt gespeichert:
wobei Entry eine schwache Referenz WeakReference implementiert, und Der Schlüssel von Entry (d. h. die von der Geschäftspartei definierte ThreadLocal-Klasse) wird in eine schwache Referenz gepackt und als Schlüssel von Entry verwendet. Die Definition der schwachen Referenz von Java besteht darin, dass die JVM, wenn sie einen Garbage-Collection-Scan durchführt und ein Objekt mit nur schwachen Referenzen findet, das Objekt sofort wiederverwendet. Dies ist ein Mittel, um einen Speicherüberlauf zu verhindern, als ThreadLocal ursprünglich entworfen wurde Der Quellcode lautet wie folgt:
Obwohl der Schlüssel in eine schwache Referenz verpackt ist und vom Garbage-Collection-Mechanismus recycelt wird, kann der Wert eine starke Referenzkette haben, wenn der Thread (Thread) nicht stirbt.
Da value
eine starke Referenz ist, solange Thread
nicht stirbt, wie z. B. ein Thread-Pool, wird diese starke Referenzkette existieren, dann ist value
wird nicht recycelt, was möglicherweise zu einem Speicherüberlauf führt. Die Referenzbeziehung lautet wie folgt: Thread ==> Entry ==> Die Kette erfordert, dass die Geschäftspartei sie im Fall von get auslöst. Dies kann der Fall sein Die Geschäftspartei erhält es nicht, oder der Schlüssel ist möglicherweise nicht leer und die expungeStaleEntry-Klasse wird nicht ausgelöst. Daher sollten Entwickler gute Gewohnheiten entwickeln und daran denken, die Methode ThreadLocal.remove()
oder ThreadLocal.set(null)
aufzurufen, wenn sie mit der Verwendung von ThreadLocal fertig sind. Code> Code>
Richtige Verwendung
public class ThreadLocalTest { /** * 未初始化的本地线程变量 */ private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>(); public static void main(String[] args) throws InterruptedException { int threadNum = 10; List<Thread> threadList = Lists.newArrayList(); for (int i = 0; i < threadNum; ++i) { long userId = i; Thread t = new Thread(() -> { try { // 设置变量值 userThreadLocal.set(new User(userId, "lanxing" + userId, "2x")); // 使用变量 doSomething(); } finally { // 移除变量 userThreadLocal.remove(); //移除ThreadLocal变量 } }, "T" + i); threadList.add(t); t.start(); } for (int i = 0; i < threadNum; ++i) { threadList.get(i).join(); } } private static void doSomething() { log.info("Use ThreadLocal variable :{}", JSON.toJSONString(userThreadLocal.get())); } } @Data @NoArgsConstructor @AllArgsConstructor class User { private Long id; private String name; private String level; }
value
是强引用,只要 Thread
不死亡时,例如线程池,这条强引用链就会存在,那么value
就不会回收,可能造成内存溢出
引用关系如下: Thread ==> ThreadLocalMap ==> Entry ==> value
但是这个消除强引用链的动作是需要业务方在get的情况下触发的,可能业务方并不会get、也可能get是key不为空,并不会触发 expungeStaleEntry 类。所以开发者要养成良好的习惯,记得用完 ThreadLocal
时,调一次ThreadLocal.remove()
方法或者 ThreadLocal.set(null)
Druckergebnis:
14:30:26.790 [T2] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden:{"id":2," level":"2x","name":"lanxing2"}14:30:26.789 [T5] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{"id":5,"level": „2x“, „name“: „lanxing5“}14:30:26.792 [T0] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{“id“:0,“level“:“2x“ ,“name“: „lanxing0“}
14:30:26.792 [T4] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{“id“:4,“level“:2x“,name ":"lanxing4"}14:30:26.792 [T8] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{"id":8,"level":"2x","name":" lanxing8"}14:30:26.791 [T1] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{"id":1,"level":"2x", "name": "lanxing1"}
14:30:26.792 [T7] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden:{"id":7,"level":"2x",name":"lanxing7"}
14: 30:26.792 [T6] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden :{"id":6,"level":"2x","name":"lanxing6"}
14:30:26.791 [T9] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden:{"id":9,"level":2x",name":lanxing9"}
14:30:26.790 [T3] INFO io.zhengsh.order.tool.ThreadLocalTest – ThreadLocal-Variable verwenden:{"id":3,"level":"2x", "name": "lanxing3"}
Das obige ist der detaillierte Inhalt vonWas ist der Grund, warum ThreadLocal in Java einen Speicherüberlauf (Out Of Memory) verursacht?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!