1. ThreadLocal 和 ThreadLocalMap,Thread的关系
- Thread里面有一个ThreadLocalMap的对象,注意这是每一个线程独有的
- ThreadLocalMap存的一个Entry,可以简单理解为键值对,键为ThreadLocal对象,值为Object(即我们存的值)
2. 如何实现
- 我们先来看看线程操纵资源类的例子代码
class threadTest{
//将 tl初始化为0
ThreadLocal<Integer> tl = ThreadLocal.withInitial(()->0);
int get(){
return tl.get();
}
void put(int val){
tl.set(tl.get()+val);
}
}
public class test22 {
public static void main(String[] args) {
threadTest threadTest = new threadTest();
for(int i=1;i<=5;i++){
int val = i;
new Thread(()->{
threadTest.put(val);
System.out.println(threadTest.get());
}).start();
}
}
}
- 每一个线程都分别执行一个put操作,设置的值就是for循环的i的值,那我们看看结果是什么
1
3
2
4
5
进程已结束,退出代码为 0
- 可以看到每一个线程操作同一个资源类的同一个ThreadLocal对象,我们发现每一个线程都是操作自己的ThreadLocal。那我们来看看ThreadLocal的set操作究竟如何实现这样的功能(get操作同理)
- 这是threadlocal的set操作
- 我们在看看 set(Thread.currentThread(), value);是怎么写的,记住这里传的参数Thread.currentThread()是指当前的线程,这是一个静态的方法,返回的就是当前线程对象!这一点很关键,有了这一个Thread.currentThread()我们可以去操作每一个线程的threadlocalmap对象了!
这里的set方法传入了当前的线程对象,然后拿到一个threadlocalmap对象
然后对这个map对象进行set操作,这就像普通的键值对赋值了,关键是我们获取的threadlocalmap究竟是什么!点进去看看源码
到这个我觉得已经真相大白了。这里传的线程t是当前线程,t.threadlcals就是当前线程的threadlocalmap
因此当线程操作同一个资源类的threadlocal对象的时候,像在这个set的过程可以分为如下几步:
1. 首先调用set方法传入的参数是要设置的value,还有一个是当前的线程对象Thread.currentThread()
2. 然后根据当前的线程对象获取到每一个Thread里面的ThreadlocalMap
3. 然后对这个threadlocalmap进行设置key-value,key是同一个资源类的threadlocal对象,value就是传入的值
4. 注意我们操作的始终是同一个对象,因此threadlocalmap设置的key始终是同一个threadlocal对象
5. 这样我们就可以实现不同的thread,通过同一个threadlocal设置不同的value
其实threadlocal的get操作也是一样的
- 根据Thread.currentThread()找到当前的线程对象
- 然后找到当前线程thread的threadlocalmap,根据同一个资源类的同一个threadlocal对象(键)获取不同的value(值)
可以通过下面的图来理解
分析就到这里,欢迎大家提出问题,共同进步