ThreadLocal 结构

1: ThreadLocal 本质是一个工具类,所set的对象并不存在ThreadLocal 对象中。

2: ThreadLocal 操作的本质是对Thread的成员变量,操作ThreadLocal.ThreadLocalMap threadLocals 

  ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; 、

inherit initial values for inheritable thread-locals from the constructing thread
所以通过MAT工具来看,一个线程有两个ThreadLocal.ThreadLocalMap 对象。

3: ThreadLocal.ThreadLocalMap 会有多个 java.lang.ThreadLocal$ThreadLocalMap$Entry 实体。
 
java.lang.ThreadLocal$ThreadLocalMap$Entry  的key是 ThreadLocal , Value是值。 如果
ThreadLocal 被置为空的话,因为java.lang.ThreadLocal$ThreadLocalMap 还持有对象
4:  java.lang.ThreadLocal$ThreadLocalMap$Entry 可能导致内存泄露。除非线程消亡。

ThreadLocal 内存泄漏的原因

从上图中可以看出,hreadLocalMap使用ThreadLocal的弱引用作为key,如果一个ThreadLocal不存在外部强引用时,Key(ThreadLocal)势必会被GC回收,这样就会导致ThreadLocalMap中key为null, 而value还存在着强引用,只有thead线程退出以后,value的强引用链条才会断掉。

但如果当前线程再迟迟不结束的话,这些key为null的Entry的value就会一直存在一条强引用链:

Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value

打断这个引用键的方式 set(),get(),remove(),是做要对这个ThreadLocal不操作的话,不会触发对value的回收。

那为什么使用弱引用而不是强

当ThreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。

key 使用强引用

当hreadLocalMap的key为强引用回收ThreadLocal时,因为ThreadLocalMap还持有ThreadLocal的强引用,如果没有手动删除,ThreadLocal不会被回收,导致Entry内存泄漏。 譬如  设置:ThreadLocal=null  以后,应该会被回收的,但实际情况是ThreadLocalMap还有一个强引用,导致无法回收

key 使用弱引用

当ThreadLocalMap的key为弱引用回收ThreadLocal时,由于ThreadLocalMap持有ThreadLocal的弱引用,即使没有手动删除,ThreadLocal也会被回收。当key为null,在下一次ThreadLocalMap调用set(),get(),remove()方法的时候会被清除value值。

譬如  设置:ThreadLocal=null  以后,强引用已没有,ThreadLocalMap还有一个弱引用,下次GC就会被回收

 

 

原文地址:https://www.cnblogs.com/liujianping/p/14785571.html