一、ThreadLocal的作用:
我初始化一个ThreadLocal变量target,初始值即为null;
在进程1里,我将它设为1;
在进程2里,我获取这个初始值,他还是null,同时我将它设成3;
在进程3里,我获取它,还是null。
各个进程对于这个变量的操作都是独立的。
二、ThreadLocal源代码讲解
1.创建ThreadLocal对象。
ThreadLocal<Integer> target = new ThreadLocal<>(); //设置ThreadLocal变量target
target.get(); //获取target值
target.set(1); //设置target值
2.ThreadLocal.get()
其中t.get()是ThreadLocal.get()方法
public T get() {
Thread t = Thread.currentThread(); //得到当前线程
ThreadLocalMap map = getMap(t); //获取当前线程的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
3.ThreadLocal.getMap()
那么得到的这个map是什么东西? 我们来看看ThreadLocal.getMap()源码
ThreadLocalMap getMap(Thread t) {
//Thread t代表的是当前线程
return t.threadLocals; //原来,每个线程有个threadLocals,它是ThreadLocalMap类型的变量
}
在Thread.java中,会对这个threadLocals进行初始化
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
4.ThreadLocal.set()
接下来我们需要知道ThreadLocalMap这个类型放了啥,我们通过ThreadLocal.set()来看,从它的源码我们发现其实他是调用了ThreadLocalMap.set()实现的
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); //其实ThreadLocal.set()是通过ThreadLocalMap.set()实现的
//map.set有两个参数,一个是ThreadLocal(也就是一开始我的target对象),一个是value
else
createMap(t, value);
}
5.ThreadLocalMap.set()
为了大家看的更清楚,我附上ThreadLocalMap.set() 的源码,随意看看就好,主要是看清楚传进去的ThreadLocal和value
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
内存泄漏
ThreadLocalMap中使用的key为ThreadLocal的弱引用,value为强引用。当ThreadLocal没被外部引用时key会被GC回收,导致key为null,而value永远无法被回收从而内存泄漏。最好每次用完ThreadLocal后手动调用remove()。
总结
最后结合我画的图,应该很清晰明了了,对于更加深层的原理我后续还会补充。同时推荐一个小白都能看得懂的讲解,很清晰透彻。