ThreadLocal提供线程本地变量。它与普通变量的区别在于,在不同的线程访问ThreadLocal(通过getset方法)拥有自己的独立副本。ThreadLocal实例一般用private static修饰。

1.ThreadLocal用法

1.1 ThreadLocal常用方法

1
2
3
4
5
6
7
8
// 返回当前线程中thread-local变量副本的值,如果当前线程的变量没有值,则该变量会被方法initialValue初始化
public T get();

// 设置当前线程的thread-local变量副本为指定的值
public void set(T value);

// 移除当前线程的thread-local变量副本的值
public void remove();

1.2 ThreadLocal使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ThreadLocalTest {

// (1) 创建线程变量
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

public static void main(String[] args) {
// (2) 设置线程变量
threadLocal.set("hello world");
// (3) 启动子线程
Thread thread = new Thread(() -> {
// (4) 子线程输出变量的值
System.out.println("thread: " + threadLocal.get());
});
thread.start();

// (5) 主线程输出线程变量的值
System.out.println("main: " + threadLocal.get());
}

}

以上实例代码运行输出内容为:

1
2
main: hello world
thread: null

代码(2)处设置了主线程的ThreadLocal副本值为hello world,故代码(5)输出为main: hello world;
代码(4)处输出子线程中ThreadLocal副本值,因为在子线程中未进行设置,故输出thread: null。

2.源码分析

2.1 set方法

  • 获取当前Thread实例t
  • 根据t获取ThreadLocalMap实例map
    • 如果map不为空,则以this(ThreadLocal对象)为key,value(泛型T)为value存入map
    • 如果map为空,则以this为firstKey,value为firstValue创建ThreadLocalMap,并赋值给t.threadLocals
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
}

2.2 get方法

  • 获取当前Thread实例t
  • 根据t获取ThreadLocalMap实例map
    • 如果map不为空,则以this(ThreadLocal对象)为key获取ThreadLocalMap.Entry实例e,如果e不为空,则返回e.value
    • 如果map为空,返回setInitialValue方法的值(方法setInitialValue返回的是方法initialValue的返回值)
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
26
27
28
29
30
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
// (1) 获取对应的ThreadLocalMap.Entry实例
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)
// (1)处获取的Entry实例为空,会重新创建一个Entry
map.set(this, value);
else
createMap(t, value);
return value;
}

protected T initialValue() {
return null;
}

2.3 ThreadLocalMap

ThreadLocalMap是只适用于管理线程本地变量的定制化的哈希表。

  • ThreadLocalMap常用方法
1
2
3
4
5
6
7
8
// 获取key关联的Entry
private Entry getEntry(ThreadLocal<?> key);

// 设置value关联key
private void set(ThreadLocal<?> key, Object value);

// 移除key对应的Entry
private void remove(ThreadLocal<?> key);
  • Entry
1
2
3
4
5
6
7
8
9
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;

Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}

参考链接: