1 定义
ThreadLocal
是存储线程局部变量的容器。
它为每一个使用该变量的线程都提供了一个变量值的副本,是Java
中一种较为特殊的线程绑定机制。
每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本发生冲突。
2 原理分析
在Java
中,Thread
类代表线程。
查看Thread
源码,如下:
public class Thread implements Runnable {
......
/**
* 与此线程相关的ThreadLocal值。
* 这个map由ThreadLocal类维护。
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* 与此线程相关的那些从父线程继承而来的ThreadLocal值。
* 这个map由InheritableThreadLocal类维护。
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
可以看出,在Thread
中是通过ThreadLocal.ThreadLocalMap
来发挥ThreadLocal
的功能的。
下面来看一下ThreadLocal
的工作原理。
ThreadLocal
提供了set(T value)
和get()
方法,用来存取线程局部变量。
2.1 ThreadLocal 的 set(T value) 方法
查看ThreadLocal
的set(T value)
方法的源码:
/**
* 设置当前线程中线程局部变量的值
*/
public void set(T value) {
// 获取当前线程对象
Thread t = Thread.currentThread();
// 获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 如果map存在,就将设置的value存入map中;如果map不存在,就创建一个map并写入值
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
getMap(t)
源码如下:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
createMap(t, value)
的源码如下:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
可以看出,getMap
是将当前线程对象t
传入,然后获取当前线程对象t
中threadLocals
的引用。因为每个线程Thread
都有自己的threadLocals
,所以getMap(t)返回的ThreadLocalMap
是每个线程自己的。
每个线程中都有一个独立的
ThreadLocalMap
副本,它所存储的值,只能被当前线程读取和修改。
ThreadLocal
类通过操作每一个线程特有的ThreadLocalMap
副本,从而实现了变量访问在不同线程中的隔离。因为每个线程的变量都是自己的,完全不会有并发错误。
ThreadLocalMap
存储的键值对中的键是this
对象指向的ThreadLocal
对象,而值就是所设置的对象。
2.2 ThreadLocal 的 get() 方法
查看ThreadLocal
的get()
方法源码:
/**
* 设置当前线程中线程局部变量的值
*/
public T get() {
// 获取当前线程对象
Thread t = Thread.currentThread();
// 获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 1.如果map存在
if (map != null) {
// 从map中获取键值对,键为当前ThreadLocal对象
ThreadLocalMap.Entry e = map.getEntry(this);
// 如果键值对存在
if (e != null) {
// 获取键值对中的值,并返回
@SuppressWarnings("unchecked")
T result = (T)e.value;