什么是ThreadLocal

它是一个线程本地变量,访问这个变量的每个线程都会有这个变量的一个本地拷贝(副本),多个线程操作的时候,实际是操作自己本地内存里面的变量,从而起到线程隔离的作用,避免线程安全问题。

如下面的演示程序:

Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Main {
static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println(threadLocal.get());
threadLocal.set(0);
System.out.println(threadLocal.get());
}, "1");

Thread thread2 = new Thread(() -> {
System.out.println(threadLocal.get());
threadLocal.set(2);
System.out.println(threadLocal.get());
}, "2");
thread.start();
thread.join();
thread2.start();
thread2.join();
}

}

它的输出是 null 0 null 2

实现的原理

通过一个Key-Value形式,将当前线程的值存入ThreadLocal中,也就是ThreadLocalMap,每个Thread对象都有一个ThreadLocalMap,Key为ThreadLocal对象,Valueh为需要缓存的值。

ThreadLocal.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

public void set(T value) {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//拿到当前线程的ThreadLocalMap
if (map != null) {
map.set(this, value);//存在这个Map就直接修改
} else {
createMap(t, value);//不存在就创建
}
}

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//不为空则从Map中取出来
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

拿到Map

ThreadLocal.java
1
2
3
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal.java
1
2
3
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLoca.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}
if (this instanceof TerminatingThreadLocal) {
TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
}
return value;
}