JDK源码06

ThreadLocal的使用

使用threadLocal提供的set方法将值保存,同时使用get来获取值,在每次使用完ThreadLocal使用remove方法对ThreadLocal进行清理用于防止内存泄露
JDK源码06

数据结构及源码

JDK源码06
在ThreadLocal中有一个自定义的hash map:ThreadLocalMap,其中使用的是数组来保存值
其中数组的类型是继承weakreference的Entry类型
JDK源码06
源码中关于继承weakreference中有这样的说明

To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys. However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space.为了处理非常大的对象和长时间使用的对象,hash table实体使用弱引用来充当map的key,但是如果该值如果不被引用的使用,只有当内存满的时候,GC才会去回收这部分内存

这就是ThreadLocal会发生内存泄露的原因,由于弱引用的原因,会导致null的key对应一个非null的value,此时entry无法释放
JDK源码06
从这里可以看出ThreadLocal使用的是循环数组的数据结构

Set方法

JDK源码06

replaceStaleEntry(key, value, i)

这个方法的名字翻译过来是替换旧的实例,从中可以大概猜出该方法的用处
其中key是entry中的key,即当前的threadLocal对象;
value是其对应的值;
i是循环数组中key为null的entry在table中的索引的值;
JDK源码06
从当前的位置向后查找key为null的entry,即无效的key,或者遇到空槽的位置,此时slotToExpunge = staleSlot
JDK源码06

expungeStaleEntry

JDK源码06

cleanSomeSlots

JDK源码06
进行对数扫描的意思是:如果当前循环数组的长度是16,则每次n向左移一位,即16->8->4->2->1;共循环四次,将其中无效的值清除,到空槽的位置停止扫描

remove

JDK源码06

调用ThreadLocalMap中remove方法,其中执行如上文所提到的expungeStaleEntry方法
JDK源码06
遇到空槽停止遍历

参考文献

源码篇:ThreadLocal你真的理解透了吗?
ThreadLocal内存溢出代码演示

上一篇:线程ThreadLocal


下一篇:ThreadLocal详解