ThreadLocal源码

1、作用:

threadlocal提供了线程内的局部变量,相比较锁而言,它是空间换时间思想,使得每个线程访问属于自己独立的变量副本。

2、结构:

ThreadLocal源码_第1张图片

每个Thread维护一个ThreadLocalMap,ThreadLocalMap中存储的是一个Entry[] table数组,Entry 中key是ThreadLocal,value是ThreadLocal中设置的值,如下图所示:

ThreadLocal源码_第2张图片

注意:当线程中的某个threadLocal被gc掉了(线程还没有消亡),此时Entry中的key值将会成为null,而value值还存在着,直到线程消亡之前,Entry中的value是无法被gc回收的,这可能造成内存泄露。为了解决此问题,源码中set或者get等方法执行时都会清除这些key为null的entry

3、方法调用

1)计算threadLocal的索引位置: threadLocal的hash值 & (table.length - 1),如下图:

2)get方法:直接获取threadLocal的索引位置对应的ThreadLocalMap中的值,索引位置如果找不到,则会从索引位置处一直向后查找直到查找到该threadLocal,源码如下:

ThreadLocal源码_第3张图片

3)set方法:  当计算出threadLocal的索引位置已经存在时,将采用开放地址法,从当前索引位置一直向后查找,如果遇到key为null的entry时就将该threadLocal存放到此位置,需要扩容时扩容到原来的2,源码如下:

ThreadLocal源码_第4张图片

ThreadLocal源码_第5张图片

4)remove方法很简单,直接源码如下:

ThreadLocal源码_第6张图片

结论:无论是set、get还有remove方法,都需要清除那些entry中key为null的对象

思考:

当我们调用set、get或者remove方法时都可以讲entry中key为null的对象给清除掉,怎么还会出现上面注意中提到的内存泄露呢,答案是这些方法都没有使用才会出现,为了避免出现内存泄露,有以下两种方式:

1、使用完后手动执行remove方法

2、将threadLocal定义为 private static ,这样可以随着线程一起消亡

你可能感兴趣的:(JDK)