ThreadLocal概念
ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
面试总结
先说Thread,也就是我们的线程类,在这个类里面有一个Map成员变量,源码如下
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
这个值初始为null。
再看ThreadLocal这个类,学习这种类,一般从set方法入手,如同一根丝线般进出,这样看源码才不会晕,源码如下
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
我们可以看到,先获得当前线程对象,再获得线程对象里的Map,进行设值。
这里再看看这个Map是什么东东
ThreadLocalMap是ThreadLocal类里面的一个静态内部类,这是一个Map结构的类,当然这里并不是探讨数据结构,
你可以简单的把他当成HashMap或者TreeMap(注:千万不要这样对面试官说,我这么说是为了你们更好理解ThreadLocal)
如同所有Map数据结构,里面必然有一个内部类Entry(不懂数据结构的可以去看看TreeMap的内容,初期不用太深入,看看里面大概有几个成员变量就行)
Entry源码:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
我们会发现这个Entry的key在父类里设置super(k),而WeakReference是一个弱引用,即这个key是弱引用
(引用分强软弱虚,平时写的就是强引用,软引用就是当你内存不足的时候gc会删除,弱引用就是每执行gc就会删除,虚引用设计堆外内存暂时不扩展)
这里就有面试点,为什么这个key是弱引用,为什么不用强引用
我们知道gc回收有个可达性算法,当一个东东不被引用就会删除,假如key用强引用即使ThreadLocal不被我们引用了,也还有一个强引用的key拉着这个ThreadLocal让他不被回收,这就是ThreadLocal的第一个内存泄漏
用弱引用就是因为弱引用不像强引用那样,相当于我们不用ThreadLocal了,gc就会吧ThreadLocal给回收
这里面试还会问第二个面试点,即哪怕ThreadLocal被回收了但是Thred线程对象里的Map还在,这就是ThreadLocal的第二个内存泄漏点
那么如何解决呢,其实很简单,不用的k-v,直接调用ThreadLocal的remove()方法就可以了,这样就不会内存泄漏,这点切记要remove
当然还可能有一些2b的问题,为什么Thred线程对象内要用Map
答:一个Thred对象可能不只是对应一个ThreadLocal,可以是多个,这里再看set方法的源码
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
set的key是什么?是this,this是什么,是当前ThreadLocal对象。
顺着这条路看源码再看看csdn别人说的,对照着学习最终才是自己的内容,任何脱离源码的讲解都是扯蛋,哪怕扯得再圆