一、TreadLocal是什么
在讲述概念前,我们还是先看下官方文档是怎么定义的:
观看官方文档,我们可以将Threadlocal做如下简单的定义:
- ThreadLocal是指的用来保存线程局部变量的一个类,既然用来保存数据,代表我们可以将ThreadLocal看做是一个容器。
- ThreadLocal是用来解决多个线程使用同一个共享变量的问题,其设计本质上讲应该是空间换取时间,简单来讲就是通过创建新的ThreadLocal容器来将共享变量的副本存放到每个线程中,以此来避免加锁带来的时间损耗,减少并发访问下的工作时间。
二、ThreadLocal的简单应用
这里我们先创建一个简单的Demo来看下ThreadLocal的应用:
public class ThreadLocalDemo_01 {
private static String str;
public static void main(String[] args) throws InterruptedException {
str = "苹果";
ThreadLocal<String> threadLocal = new ThreadLocal<String>();
threadLocal.set(str);
Stream.of("华为", "oppo", "锤子").forEach(s -> {
Thread thread = new Thread(()->{
String string = threadLocal.get();
System.out.println(Thread.currentThread().getName()+" 线程拿到的变量值是:"+string);
str =s ;
threadLocal.set(str);
string = threadLocal.get();
System.out.println(Thread.currentThread().getName()+" 线程更新后的变量值是是:"+string);
},s);
thread.start();
});
Thread.sleep(1_000);
String string = threadLocal.get();
System.out.println(Thread.currentThread().getName()+" 线程拿到的变量值是:"+string);
System.out.println("静态变量str的值为"+str);
}
}
打印结果:
虽然我们往ThreadLocal里存放的都是相同的静态变量str,但是在str的值改变的时候,存放在ThreadLocal中的变量副本并没有发生改变,这就保证了我们引用的一直都是我们希望使用的变量值。
三、ThreadLocal的源码分析
这里我们在简单的分析下ThreadLocal的源码,来看下他是如何实现对线程局部变量的存储,这里我把有意义的源码站出来:
// set方法
public void set(T paramT) {
Thread localThread = Thread.currentThread();
ThreadLocalMap localThreadLocalMap = getMap(localThread);
if (localThreadLocalMap != null) {
localThreadLocalMap.set(this, paramT);
} else {
createMap(localThread, paramT);
}
}
// 获取参数
public T get() {
Thread localThread = Thread.currentThread();
ThreadLocalMap localThreadLocalMap = getMap(localThread);
if (localThreadLocalMap != null) {
ThreadLocal.ThreadLocalMap.Entry localEntry = localThreadLocalMap.getEntry(this);
if (localEntry != null) {
Object localObject = value;
return (T) localObject;
}
}
return (T) setInitialValue();
}
// 获取容器
ThreadLocalMap getMap(Thread paramThread) {
return threadLocals;
}
// 创建容器
void createMap(Thread paramThread, T paramT) {
threadLocals = new ThreadLocalMap(this, paramT);
}
//容器的本质
ThreadLocalMap(ThreadLocal<?> paramThreadLocal, Object paramObject) {
table = new Entry[16];
int i = threadLocalHashCode & 0xF;
table[i] = new Entry(paramThreadLocal, paramObject);
size = 1;
setThreshold(16);
}
这里我们简单的分析下源码,其实通过ThreadLocal的源码可以证实我刚才的理论,ThreadLocal的本质就是一个容器,他是以当前的线程为key,传入的object对象为value进行存储,这样当不同的参数调用get方法的时候,他会以线程作为key去查找value,已达到避免多个线程对同一个变量进行修改的目的。
四、InheritableThreadLocal
作为ThreadLocal的子类,它其实主要是为了实现父子线程之间的变量共享问题,这个由于平时应用并不是很多,所以我这边就不做赘述,感兴趣的同学可以看下这篇博客:
https://zhuanlan.zhihu.com/p/101780720
写这篇文章时刚好感到成都爆发新冠疫情,公司人心惶惶,这篇可能写的有些粗略,如果之后有机会我会将这篇重新的写一下,多增加一些举例,好了就吐槽到这吧!