1、定义
ThreadLocal类可以实现线程本地存储的作用,它是线程Thread的局部变量,每个线程Thread使用独立的副本。
2、要点
- 不存在线程共享问题
- 一般使用private static修饰
3、ThreadLocal实现原理
首先,一个线程可以有多个ThreadLocal对象,是因为线程Thread中维护了一个ThreadLocal.ThreadLocalMap的map,如下所示
Thread.java
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
我们使用的get()、set()方法其实都是调用了这个ThreadLocalMap类对应的get()、set()方法
ThreadLocal.java
public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 如果map不为空
if (map != null) {
// 获取ThreadLocal对象的实例
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
...
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
// 如果ThreadLocalMap 存在,则把该ThreadLocal实例值放入map
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);
}
更多详细源码参考jdk
其中ThreadLocalMap中key值使用ThreadLocal的类对象属性threadLocalHashCode,它使用的AtomicInteger的getAndAdd方法来保证唯一
最后,线程的所有ThreadLocal变量都放在了当前线程的ThreadLocalMap(只有一个)中,不同的ThreadLocal变量只是传递了不同变量值并且提供获取其变量值的入口。
4、使用场景
ThreadLocal 适用于变量在线程间隔离而在方法或类间共享的场景,比如上下文传递信息。
5、使用示例
先看一下jdk中给的示例:给每个不同的线程生成唯一id,并保持在ThreadLocal变量中
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// 使用原子类Atomic integer生成唯一id
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
public static int get() {
return threadId.get();
}
}