什么是ThreadLocal?
ThreadLocal从字面意思理解是线程本地变量。变量好理解就是存取值,那线程本地如何理解呢?又是如何实现的呢?我们来探究一下。
关于线程本地变量的理解总体来说有两点:
- 在某个线程内使用ThreadLocal#set()设置值,只在当前线程有效不会影响其他线程
- 在某个线程内使用ThreadLocal#get()获取值,只能获取在当前线程设置过的值
以上就是线程本地变量的理解。
实现原理
每个线程类都有一个Map结构的成员变量ThreadLocal.ThreadLocalMap threadLocals来存储每个ThreadLocal对应的value值。不管是get操作还是set操作,首先都会去获取当前线程,然后去这个线程的Map结构中去做存取操作。
调用关系:
弱引用WeakReferencer
特性:对象在只有弱引用的情况下,JVM随时会回收该对象。
在ThreadLocalMap中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继承WeakReference,通过super()将当前ThreadLocal传入WeakReference。图中的T referent实际为ThreadLocal。因此在Entry中ThreadLocal在没有其他引用的情况下,可以随时被回收。
内存泄露问题
一旦Entry中的ThreadLocal实例仅被弱引用引用,就会被JVM随时回收,导致Entry中的value泄露。即value无法被回收,但实际已没有意义。
虽然源码中有些优化,但写代码的时候最好还是手动调用ThreadLocal#remove()显示删除无用的Entry对象。