介绍
ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal像是一个map,map的键就是每一个线程,值就是变量副本
使用
public class ThreadLocalDemo {
private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
public Integer getNext() {
Integer integer = threadLocal.get();
threadLocal.set(++integer);
return integer;
}
public static void main(String[] args) {
ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
while (true) {
System.out.println(Thread.currentThread().getName() + threadLocalDemo.getNext());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
上面的代码中,每一个线程的值都是从0开始递增,各个线程之间互不影响。
原理解析
首先查看get()方法的源代码:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
// 这里可以看到最终的值是从这里拿到的,也就是说值会存在ThreadLocal下面的ThreadLocalMap里面的Entry里面的value里面
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)
map.set(this, value);
else
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {
// 这个创建ThreadLocalMap的方法比较有趣的是它将创建好后的map赋值给了当前线程的一个属性
// 而在Thread类中确实有这样一个属性,如下。因此ThreadLocalMap是属于每一个线程的
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocal.ThreadLocalMap threadLocals = null;