ThreadLocal,简单翻译过来就是本地线程,但是直接这么翻译很难理解ThreadLocal的作用,如果换一种说法,可以称为线程本地存储。简单来说,就是ThreadLocal为共享变量在每个线程中都创建一个副本,每个线程可以访问自己内部的副本变量。这样做的好处是可以保证共享变量在多线程环境下访问的线程安全性。
通过一个简单的例子来演示一下ThreadLocal的作用,这段代码是定义了一个静态的成员变量num
,然后通过构造5个线程对这个num
做递增。
public class ThreadLocalDemo {
private static Integer num=0;
public static void main(String[] args) {
Thread[] threads=new Thread[5];
for(int i=0;i{
num+=5;
System.out.println(Thread.currentThread().getName()+" : "+num);
},"Thread-"+i);
}
for(Thread thread:threads){
thread.start();
}
}
}
----------------------------------------------------------
运行结果
Thread-0 : 5
Thread-1 : 10
Thread-2 : 15
Thread-3 : 20
Thread-4 : 25
每个线程都会对这个成员变量做递增,如果线程的执行顺序不确定,那么意味着每个线程获得的结果也是不一样的。
public class ThreadLocalDemo {
private static final ThreadLocal local=new ThreadLocal(){
protected Integer initialValue(){
return 0; //通过initialValue方法设置默认值
}
};
public static void main(String[] args) {
Thread[] threads=new Thread[5];
for(int i=0;i{
int num=local.get().intValue();
num+=5;
System.out.println(Thread.currentThread().getName()+" : "+num);
},"Thread-"+i);
}
for(Thread thread:threads){
thread.start();
}
}
}
-------------------------------------------------------------
运行结果
Thread-0 : 5
Thread-4 : 5
Thread-2 : 5
Thread-1 : 5
Thread-3 : 5
从结果可以看到,每个线程的值都是5,意味着各个线程之间都是独立的变量副本,彼此不相互影响。ThreadLocal会给定一个初始值,也就是initialValue()
方法,而每个线程都会从ThreadLocal中获得这个初始化的值的副本,这样可以使得每个线程都拥有一个副本拷贝。
set方法是设置一个线程的局部变量的值,相当于当前线程通过set设置的局部变量的值,只对当前线程可见。
public void set(T value) {
Thread t = Thread.currentThread();//获取当前执行的线程
ThreadLocalMap map = getMap(t); //获得当前线程的ThreadLocalMap实例
if (map != null)//如果map不为空,说明当前线程已经有了一个ThreadLocalMap实例
map.set(this, value);//直接将当前value设置到ThreadLocalMap中
else
createMap(t, value); //说明当前线程是第一次使用线程本地变量,构造map
}
Thread.currentThread
获取当前执行的线程getMap(t)
,根据当前线程得到当前线程的ThreadLocalMap对象,这个对象具体是做什么的?稍后分析- 如果map不为空,说明当前线程已经构造过ThreadLocalMap,直接将值存储到map中
- 如果map为空,说明是第一次使用,调用
createMap
构造
ThreadLocalMap map=getMap(t)
获得一个ThreadLocalMap对象,那这个对象是干嘛的呢?其实不用分析,基本上也能猜测出来,Map是一个集合,集合用来存储数据,那么在ThreadLocal中,应该就是用来存储线程的局部变量的。ThreadLocalMap
这个类很关键。
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
t.threadLocals实际上就是访问Thread类中的ThreadLocalMap这个成员变量:
public
class Thread implements Runnable {
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
从上面的代码发现每一个线程都有自己单独的ThreadLocalMap实例,而对应这个线程的所有本地变量都会保存到这个map内。
ThreadLocalMap是在哪里构造? 在set
方法中,有一行代码createmap(t,value);
,这个方法就是用来构造ThreadLocalMap,从传入的参数来看,它的实现逻辑基本也能猜出出几分吧。
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
Thread t
是通过Thread.currentThread()
来获取的表示当前线程,然后直接通过new ThreadLocalMap
将当前线程中的threadLocals
做了初始化 ThreadLocalMap是一个静态内部类,内部定义了一个Entry对象用来真正存储数据。
static class ThreadLocalMap {
static class Entry extends WeakReference
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?