简介
ThreadLocal是JDK提供的,提供线程本地变量,主要用来存放线程独有变量和解决参数传递问题的。
例子
public static void main(String
[] args
) {
ThreadLocal threadLocal
= new ThreadLocal();
for(int i
=0;i
<3;i
++){
new Thread(()->{
double random
= Math
.floor(Math
.random()*10);
threadLocal
.set(random
);
System
.out
.println("设置线程"+Thread
.currentThread().getName()+",线程变量:"+random
);
System
.out
.println("查看线程"+Thread
.currentThread().getName()+",线程变量:"+threadLocal
.get());
}).start();
}
}
设置线程Thread
-2,线程变量:
4.0
设置线程Thread
-0,线程变量:
9.0
设置线程Thread
-1,线程变量:
5.0
查看线程Thread
-0,线程变量:
9.0
查看线程Thread
-2,线程变量:
4.0
查看线程Thread
-1,线程变量:
5.0
可以看出,每个线程的变量是隔离开的,避免了出现线程不安全的问题,ThreadLocal是如何实现的呢?
原理
ThreadLocalMap
public class Thread implements Runnable {
ThreadLocal
.ThreadLocalMap threadLocals
= null
;
}
ThreadLocalMap是真正存储数据的地方,ThreadLocalMap在各个线程中,为线程独有的
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
);
}
ThreadLocalMap
getMap(Thread t
) {
return t
.threadLocals
;
}
void createMap(Thread t
, T firstValue
) {
t
.threadLocals
= new ThreadLocalMap(this, firstValue
);
}
从set方法中第二行代码ThreadLocalMap map = getMap(t);这段代码是获取当前线程的ThreadLocalMap,然后进行设置值,通过getMap方法可以看出,线程本地变量并不是存储在ThreadLocal,而是存储在各自线程的ThreadLocalMap threadLocals中的,ThreadLocal只是相当于一个工具类,对ThreadLocalMap进行操作而已。
get方法
public T
get() {
Thread t
= Thread
.currentThread();
ThreadLocalMap map
= getMap(t
);
if (map
!= null
) {
ThreadLocalMap
.Entry e
= map
.getEntry(this);
if (e
!= null
) {
@SuppressWarnings("unchecked")
T result
= (T
)e
.value
;
return result
;
}
}
return setInitialValue();
}
private T
setInitialValue() {
T value
= initialValue();
Thread t
= Thread
.currentThread();
ThreadLocalMap map
= getMap(t
);
if (map
!= null
)
map
.set(this, value
);
else
createMap(t
, value
);
return value
;
}
get方法是获取当前线程的ThreadLocalMap,然后通过将ThreadLocal当做key,从ThreadLocalMap中获取到相应的Entry,Entry里包含了key和value,最后将value返回,如果没有key的值,就会调用setInitialValue方法,setInitialValue方法会初始化一个默认值,默认值是null,也可以重写initialValue,获得自己想要的默认值,如果没有创建ThreadLocalMap,则创建,然后返回默认值
remove方法
public void remove() {
ThreadLocalMap m
= getMap(Thread
.currentThread());
if (m
!= null
)
m
.remove(this);
}
remove方法十分简单,就是删除ThreadLocalMap中key为当前ThreadLocal的数据
总结
通过看源码,可以得出
ThreadLcoal只是一个用来操作ThreadLocalMap的一个工具类和充当ThreadLocalMap的key。ThreadLocalMap是真正存储数据的,但是ThreadLocalMap是存储在每个线程中的。每个线程都有各自的ThreadLocalMap,这也是实现线程隔离的根本原因。
下文
ThreadLocalMap详解及源码解读