这是我参与更文挑战的第8天,活动详情查看: 更文挑战
1、ThreadLocal是什么?
ThreadLocal和synchronized关键字都是用来保证多线程情况下的并发访问,但是ThreadLocal和synchronized关键字有本质的区别
synchronized是利用锁的机制让代码在某一个时刻只有一个线程去访问一段代码或者变量。
而ThreadLocal它是为每一个线程提供一个变量的副本,使每个线程都有一个变量的副本,每个线程都访问自己的变量副本,这就实现了所谓的线程隔离 比如Spring就用到了ThreadLocal,Spring在实现事务的时候,就用到了ThreadLocal,每个线程来保存自己的连接, 说Spring的事务可能做Android的没接触过,但是Handler 的Looper类就是利用了ThreadLocal的特性,保证每个线程只存在一个Looper对象
2、ThreadLocal的使用
public class UseThreadLocal {
private static ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {//初始化变量
return 1;
}
};
public static void main(String[] args) {
for (int i=0;i<3;i++){
new Thread(new TestThread(i)).start();
}
}
public static class TestThread implements Runnable{
int id;
public TestThread(int id) {
this.id=id;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":start");
Integer s= threadLocal.get();
s=s+id;
threadLocal.set(s);
System.out.println(Thread.currentThread().getName()+":"+ threadLocal.get());
}
}
}
运行结果
看我们的运行结果,Thread0,Thread1,Thread2的输出结果分别是1,2,3,没有相互影响,达到了我们预期的效果,这三个线程分别拥有了Interger的副本
我们在看一下不用ThreadLocal的效果
private static Integer count=new Integer(1);
public static void main(String[] args) {
for (int i=0;i<3;i++){
new Thread(new TestThread(i)).start();
}
}
public static class TestThread implements Runnable{
int id;
public TestThread(int id) {
this.id=id;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":start");
count=count+id;
System.out.println(Thread.currentThread().getName()+":"+count );
}
}
运行结果
运行结果就是,他们没有隔离,三个线程操作的是同一个对象,而不是对象副本
3、ThreadLocal的实现
ThreadLocal看他的实现,从哪看起呢?咱们就从threadLocal的set方法和get方法看起
get方法
我们在这个方法里可以看到什么呢?
有一个存储的Map
每次get的时候会先获取当前线程的ThreadLocalMap,我们去看一下getMap方法
threadLocals每个线程里都会有的对象
而且这个ThreadLocalMap是定义在ThreadLocal里面的 然后我们再往下看 get完map,如果为空就返回初始值,如果不为空,就返回以当前的ThreadLocal对象为Key的一个Entry对象,然后再返回Entry的value
咱们再去看看代码里的Entry
emmm 跟我说的一样,但是xdm你看一下上边的代码下边还有一个Entry数组,为什么要用数组呢?因为我们可能不仅定义一个ThreadLocal嘛,这不就说的通了
再看设置初始值的方法
他就是以当前的ThreadLocal为Key,以初始值为value存进ThradLocalMap里的Entry数组里
ThreadLocalMap 的set方法
看到这里大家应该明白它具体是怎么实现的了吧
我们再看一下 ThreadLocal的set方法
和设置初始值的方法差不太多 我们ThreadLocal在设置值的时候也就是执行set方法的时候,它会去设置每个线程对象里边的LocalMap里键为ThreadLocal的value,这样就实现了每个线程里的变量副本 看到这里大家应该知道ThreadLocal是怎么实现的了吧!如果有的xdm看到这里感觉还是脑袋瓜子嗡嗡的,咱们上图
3、总结
我们从ThreadLocal的作用和使用,和源码里是怎么实现的学习了ThreadLocal!如有错误之处请大佬们在评论区提出!希望大佬们一键三连!