ThreadLocal 解决什么问题
ThreadLocal 是为了解决对象不能被多线程共享访问的问题,通过 threadLocal.set() 方法将对象实例保存在每个线程自己所拥有的 threadLocalMap 中,这样每个线程都使用自己的对象实例,彼此不会影响从而达到了隔离的作用,解决了对象在被共享访问时带来的线程安全问题。
先把 Thread、ThreadLocal、ThreadLocalMap 的关系捋一捋:

可以看到,在 Thread 中持有一个 ThreadLocalMap,ThreadLocalMap 又是由 Entry 来组成的,在 Entry 里面有 ThreadLocal 和 value。
ThreadLocal 为什么会内存泄漏
首先是因为 ThreadLocal 是基于 ThreadLocalMap 实现的,其中 ThreadLocalMap 的 Entry 继承了 WeakReference,而 Entry 对象中的 key 使用了 WeakReference 封装,也就是说,Entry 中的 key 是一个弱引用类型,对于弱引用来说,它只能存活到下次 GC 之前。
如果此时一个线程调用了 ThreadLocalMap 的 set 设置变量,当前的 ThreadLocalMap 就会新增一条记录,但由于发生了一次垃圾回收,这样就会造成一个结果:key 值被回收掉了,但是 value 值还在内存中,而且如果线程一直存在的话,那么它的 value 值就会一直存在。
这样被垃圾回收掉的 key 就会一直存在一条引用链:Thread -> ThreadLocalMap -> Entry -> Value:

就是因为这条引用链的存在,就会导致如果 Thread 还在运行,那么 Entry 不会被回收,进而 value 也不会被回收掉,但是 Entry 里面的 key 值已经被回收掉了。
这只是一个线程,如果再来一个线程,又来一个线程…多了之后就会造成内存泄漏。知道是怎么造成内存泄漏之后,接下来要做的事情就好说了,因为 value 值没有被回收掉所以才会导致内存泄露。
所以在使用完 key 值之后,将 value 值通过 remove 方法 remove 掉,这样的话内存中就不会有 value 值了,也就防止了内存泄漏。
ThreadLocal 是基于 ThreadLocalMap 实现的
在源码中能够看到下面这几行代码:
public class ThreadLocal<T> {
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
}







