以下是 Thread
类中的部分源代码:
public class Thread implements Runnable {
...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class.(与此线程有关的ThreadLocal值。由ThreadLocal类维护) */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.(与此线程有关的
* InheritableThreadLocal值。由InheritableThreadLocal类维护)
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
...
}
从上面可以看出,Thread
类中有一个 threadLocals
和 inheritableThreadLocals
变量,它们都是 ThreadLocalMap
类型的变量,可以把 ThreadLocalMap
理解为ThreadLocal
类实现的定制化的 HashMap
。默认情况下,这两个变量都是 null,只有当前线程调用 ThreadLocal
类的 set
或 get
方法时才创建它们,实际上调用这两个方法的时候,真正调用的是 ThreadLocalMap
类对应的 get()
、set()
方法。
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);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
最终的变量,是放在当前线程的 ThreadLocalMap
中,而不是存在 ThreadLocal
上,ThreadLocal
可以理解为只是ThreadLocalMap
的封装,传递了变量值。ThrealLocal
类中,可以通过 Thread.currentThread()
获取到当前的线程对象,可以直接通过 getMap(Thread t)
访问到该线程的ThreadLocalMap
对象。
ThreadLocalMap
是ThreadLocal
的静态内部类。
ThreadLocal 内存泄露问题
ThreadLocalMap
中使用的 key 为 ThreadLocal
的弱引用,而 value 是强引用。所以,如果 ThreadLocal
没有被外部强引用的情况下,在进行垃圾回收的时候, key 就会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap
中就会出现 key 为 null 的 Entry。此时,如果不做任何措施的话,value 就永远无法被 GC 回收,这个时候可能就会产生内存泄露。ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()
、get()
、remove()
方法的时候,都会清理掉 key 为 null 的记录。所以,使用完 ThreadLocal
方法后,最好手动调用下 remove()
方法。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
弱引用介绍:
如果一个对象只具有弱引用,那就类似于可有可无的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java 虚拟机就会把这个弱引用加入到与之关联的引用队列中。
网友评论