public class ThreadLocalTest {
private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
public static void main(String[] args){
//创建第一个线程
Thread threadA = new Thread(()->{
threadLocal.set("ThreadA:" + Thread.currentThread().getName());
System.out.println("线程A本地变量中的值为:" + threadLocal.get());
});
//创建第二个线程
Thread threadB = new Thread(()->{
threadLocal.set("ThreadB:" + Thread.currentThread().getName());
System.out.println("线程B本地变量中的值为:" + threadLocal.get());
});
//启动线程A和线程B
threadA.start();
threadB.start();
}
}
上面这段代码执行结果为
线程A本地变量中的值为:ThreadA:Thread-0
线程B本地变量中的值为:ThreadB:Thread-1
public class ThreadLocalTest {
private static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
public static void main(String[] args){
//创建第一个线程
Thread threadA = new Thread(()->{
threadLocal.set("ThreadA:" + Thread.currentThread().getName());
System.out.println("线程A本地变量中的值为:" + threadLocal.get());
threadLocal.remove();
System.out.println("线程A删除本地变量后ThreadLocal中的值为:" + threadLocal.get());
});
//创建第二个线程
Thread threadB = new Thread(()->{
threadLocal.set("ThreadB:" + Thread.currentThread().getName());
System.out.println("线程B本地变量中的值为:" + threadLocal.get());
System.out.println("线程B没有删除本地变量:" + threadLocal.get());
});
//启动线程A和线程B
threadA.start();
threadB.start();
}
}
上面这段代码执行结果为
线程A本地变量中的值为:ThreadA:Thread-0
线程B本地变量中的值为:ThreadB:Thread-1
线程B没有删除本地变量:ThreadB:Thread-1
线程A删除本地变量后ThreadLocal中的值为:null
由上面的代码可以看出AB线程中对ThreadLocal的操作是互不影响的.
下面我们就从源码的角度来剖析一下
public T get() {
Thread t = Thread.currentThread();
ThreadLocal.ThreadLocalMap map = this.getMap(t);
if (map != null) {
ThreadLocal.ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
T result = e.value;
return result;
}
}
return this.setInitialValue();
}
从以上的返回值来看,get()方法最后会返回种结果
1.从Thread.currentThread()中取的结果
2.从this.setInitialValue()返回的结果
接下来只需要看一下这里两个地方是取得值是啥玩意
首先来看getMap()方法
ThreadLocal.ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
从此可以看出get方法是返回的当前线程Thead的threadLocals变量
接下来我们来看一下this.setInitialValue()中的逻辑
private T setInitialValue() {
T value = this.initialValue();
Thread t = Thread.currentThread();
ThreadLocal.ThreadLocalMap map = this.getMap(t);
if (map != null) {
map.set(this, value);
} else {
this.createMap(t, value);
}
if (this instanceof TerminatingThreadLocal) {
TerminatingThreadLocal.register((TerminatingThreadLocal)this);
}
return value;
}
该代码中主要的逻辑为将的this.initialValue()中的值设置到当前线程中的Map中,也就是threadLocals中,并且返回value。如果threadLocals为空,则新建一个ThreadLocalMap存入当前线程的threadLocals变量中。
接下来我们来看一下initialValue中的逻辑,可以看到返回的是null,子类也可以覆写该方法
protected T initialValue() {
return null;
}
createMap()方法,这里划重点,要考
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocal.ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
this.table = new ThreadLocal.ThreadLocalMap.Entry[16];
int i = firstKey.threadLocalHashCode & 15;
this.table[i] = new ThreadLocal.ThreadLocalMap.Entry(firstKey, firstValue);
this.size = 1;
this.setThreshold(16);
}
ThreadLocalMap就是ThreadLocal的精髓所在
从ThreadLocalMap的构造函数我们可以看到,每个存入ThreadLocal中的值都被存入的table中,而table中则是Entry,Entry的key是ThreadLocal对象hash之后的值,value则是需要隔离的对象。
到这里我们就可以看出ThreadLocal储存的原理了
当我们向线程中取出value值时,实际上就是从当前线程的ThreadLocalMap中取值,而每个线程都会持有一个ThreadLocalMap(ThreadLocalMap的key为ThreaLocal做hash之后的值,value为需要存入线程中的变量),所以每个线程对ThreadLocalMap的操作是互相不影响的
现在我们来看一下set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocal.ThreadLocalMap map = this.getMap(t);
if (map != null) {
map.set(this, value);
} else {
this.createMap(t, value);
}
}
通过我们前面对get方法的解读,现在看set方法就容易很多了。
将当前线程的threadLocals取出然后往里面set值,如果map为空,则新建
最后我们看一下remove方法
public void remove() {
ThreadLocal.ThreadLocalMap m = this.getMap(Thread.currentThread());
if (m != null) {
m.remove(this);
}
}
就是将当前线程的threadLocals取出然后干掉,具体怎么干掉的,就参考ThreadLocalMap的构造函数,反向操作,自己脑补一下吧。