1. ThreadLocal 类
1.1 get()
public T get() {
// 当前线程
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
1.2 getMap(Thread)
获取当前线程的 threadLocals 变量 (每个线程都有一个自己的ThreadLocalMap)
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
取自 Thread 类的 ThreadLocal.ThreadLocalMap threadLocals = null;
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
}
Thread 有一个 ThreadLocalMap 类型的成员变量 threadLocals, 该变量用来存储变量副本,存储以 ThreadLocal 为键,本地线程变量为值的键值对
1.3 set(T value)
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
1.4 createMap(Thread, T)
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocal.ThreadLocalMap(this, firstValue);
}
1.5 initialValue()
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
protected T initialValue() {
return null;
}
1.6 remove()
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
2. ThreadLocalMap 类
public class ThreadLocal<T> {
static class ThreadLocalMap {
static class Entry extends WeakReference<ThreadLocal<?>> { }
}
}
- ThreadLocal 里有静态内部类
ThreadLocalMap
- ThreadLocalMap 里有静态内部类 Entry 用来存放数据(键值对),且继承弱引用 WeakReference
2.1 Entry 类
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
ThreadLocal<?> 弱引用 作为 key
2.2 set(ThreadLocal<?> key, Object value)
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
//...
tab[i] = new Entry(key, value);
// ...
}
3. ThreadLocal 内存泄露问题
内存泄露,即某个对象不再有用,但是占用的内存却不能被回收
![](https://img.haomeiwen.com/i20154612/aa4ccbd2d0206db4.png)
虽然 ThreadLocalMap 中的 key 是弱引用,当不存在外部强引用的时候,就会自动被回收,但是 Entry 中的 value 依然是强引用。这个 value 的引用链条如下:
![](https://img.haomeiwen.com/i20154612/93e7ba0349555543.png)
可以看到,只有当 Thread 被回收时,这个 value 才有被回收的机会,否则,只要线程不退出 (比如线程池需要保持很久),value 总是会存在一个强引用。
3.1 如何避免内存泄露
调用 remove 方法,就会删除对应的 Entry 对象,可以避免内存泄露
4. ThreadLocal 应用场景
4.1 应用场景
场景一:全局存储用户信息
场景二:在Spring事务管理中的应用ThreadLocal
4.2 ThreadLocal 慎用的场景
场景一:线程池里线程调用 ThreadLocal,
线程池的线程都是复用的,在线程池中线程非常难结束甚至于永远不会结束,线程持续的时间将不可预测
场景二:异步程序中使用ThreadLocal
因为线程将请求发送后,不会等待远程返回结果,而是继续向下运行,真正的返回结果得到后,处理的线程可能是其他的线程
网友评论