ThreadLocal
2020-04-30 本文已影响0人
lsh的学习笔记
从使用说起
ThreadLocal<String> name = new ThreadLocal();
ThreadLocal<String> school = new ThreadLocal();
name.set("张三");
System.out.println(name.get());
school.set("张三");
System.out.println(school.get());
从示例代码可以看出,一个ThreadLocal对象只能
存储一个
数据,如果想存储多个数据,就需要创建多个ThreadLocal对象。
看看源码
class Thread {
//内部持有ThreadLocalMap
ThreadLocal.ThreadLocalMap threadLocals;
}
// ThreadLocal 类
// get 方法
public void set(T value) {
Thread t = Thread.currentThread();
// 注意这个ThreadLocalMap是从当前Thread对象中获取的;
ThreadLocalMap map = getMap(t);
if (map != null)
// 注意这里的key,传的是this;
map.set(this, value);
else
createMap(t, value);
}
// 从线程中获取 Map
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// get 方法
public T get() {
Thread t = Thread.currentThread();
// 从当前线程中获取 Map;
ThreadLocalMap map = getMap(t);
if (map != null) {
// 根据 key 获取 value;
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
// 类似,但不是 HashMap,注意构造器;
static class ThreadLocalMap {
// 内部保存数据的数组
private Entry[] table;
// Map的大小
private int size = 0;
// 构造器的key,写死存储的Entry的key为ThreadLocal类型;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
// set方法也限制死了 key;
private void set(ThreadLocal<?> key, Object value) {
// 省略代码
}
static class Entry extends WeakReference<ThreadLocal<?>> {
// 关联 ThreadLocal 对象
Object value;
// 注意这个构造器,默认传的key就是ThreadLocal对象
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
数据结构
从上面的源码,我们可以分析得:当前线程 Thread 对象内部有一个类似 HashMap 的类,这个类的Entry 保存着当前线程的数据,Entry 的 key 是ThreadLocal对象,value 是用户 set 的值。
如果画图的话,就是如下这张图:
1内存泄露
使用线程池
的时候,线程Thread对象
结束是不会销毁的,会再次使用的就可能出现内存泄露 。(在web应用中,每次http请求都是一个线程,tomcat容器配置使用线程池时会出现内存泄漏问题)。而且容易造成数据污染
。
解决
每次使用后在finally块
中remove
掉。