引用百度的一段介绍:ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
为了验证ThreadLocal的使用,现手写的如下代码:
public class Demo01 {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
for (int i = 0; i < 5; i++) {
threadLocal.set(threadLocal.get()+1);
System.out.println(threadLocal.get());
}
});
thread1.start();
Thread thread2 = new Thread(()->{
for (int i = 0; i < 5; i++) {
threadLocal.set(threadLocal.get()+1);
System.out.println(threadLocal.get());
}
});
thread2.start();
}
}
结果就是12345各自打印了2次,可见ThreadLocal的确具有线程隔离性,为了进一步探究,于是点进去set方法查看究竟
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
由于作者英文水平较差,所以借用百度翻译 设置此线程局部变量的当前线程副本设置为指定的值。大多数子类都不需要这样做重写此方法,仅依赖{@link#initialValue}方法来设置线程局部变量的值。
其逻辑实现大致为:
1.获取到当前运行的线程,
2.通过获取到的当前线程再获取一个ThreadLocalMap 对象 map
3.map不存在就新建,map有值则覆盖
那ThreadLocalMap 又是干什么的呢?
点进去getMap(t)方法,源码如下:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
再次点进去,发现Thread类有一个属性叫threadLocals,其类型就是ThreadLocalMap 类型,而ThreadLocalMap又是ThreadLocal的一个静态内部类,也就是全局唯一的一个类,其key为ThreadLocal类型,value为Object类型。
总结为:
每一个线程对象,其内部维护了一个ThreadLocalMap对象,这个ThreadLocalMap对象毫无疑问是线程安全的。如若某线程执行中操作了一个ThreadLocal对象,那么该线程就会创建一个ThraedLocalMap对象即对应上述的threadLocals,若线程从执行到结束均未操作ThreadLocal对象,那么该线程的threadLocals总是为null。