案例
public class ThreadLocalDemo {
//初始化一个ThreadLocal对象 初始值设置为0
private static final ThreadLocal<Integer> localA = new ThreadLocal(){
@Override
protected Object initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
System.out.println("thread1 threadLocalA value " + localA.get());
localA.set(localA.get() + 5);
System.out.println("thread1 after modify threadLocalA value " + localA.get());
});
thread1.start();
thread1.join();
Thread thread2 = new Thread(() -> {
System.out.println("thread2 threadLocalA value " + localA.get());
});
thread2.start();
}
执行结果
从上面的案例中可以看到,在thread1中对threadLocal.set()的修改只会影响thread1中threadLocal.get(),对其他线程不会产生影响,因此在高并发场景下,我们可以定义threadLocal在初始化的时候给定统一的初始值,而在后续多线程的操作中又实现了数据的隔离。
源码分析
ThreadLocal.ThreadLocalMap threadLocals = null;
每一个Thread对象中对维护了一个ThreadLocalMap对象,他是ThreadLocal的一个内部类,用来保证每个Thread之间对ThreadLocal操作的相互隔离。
ThreadLocal.get()
public T get() {
//获取执行threadLocal.get()的线程对象
Thread t = Thread.currentThread();
//获取该线程的成员属性 threadLocalMap
ThreadLocalMap map = getMap(t);
/**
*ThreadLocalMap getMap(Thread t) {
* return t.threadLocals;
* }
**/
//如果map不为空,说明已经被其他threadLocal对象通过调用threadLocal.get()完成了thread.threadLocalMap的初始化
if (map != null) {
//使用当前的threadLocal对象作为key,获取当前thread.threadLocalMap的Entry对象
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
//获取entry的值返回
T result = (T)e.value;
return result;
}
}
//thread.threadLocalMap初始化操作
return setInitialValue();
}
private T setInitialValue() {
//获取threadLocal的初始值默认为null,可以通过案例中的方式重写initial方法,定义ThreadLocal的初始值
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
//thread.threadLocalMap中设置一个Entry key:ThreadLocal value:ThreadLocal的初始值
map.set(this, value);
else
//初始化thread.threadLocalMap.并设置一个Entry key:ThreadLocal value:ThreadLocal的初始值
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {
// this代表当前线程操作的threadLocal对象
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal.set(T)
代码和get类似,第一次在一个thread中操作某个threadLocal的set方法,会初始化该thread.threadLoalMap成员属性,并设置一个Entry : key:操作的threadLocal对象 value threadLocal的初始值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
总结
由此可以看到,我们执行ThreadLocal.get()和ThreadLocal.set()并不会真正的修改ThreadLocal对象里面的值,ThreadLocal对象只是维护一个初始值,接下来仅仅是作为Key去thread.threadLocalMap的线程成员属性中去获取或者设置一个值。所以我们对threadLocal的操作是线程隔离的。并且一个线程可以维护多个ThreadLocal对象,存储在thread.threadLocalMap的Thread的成员属性中。