1.ThreadLocal 作用
作用:为变量在线程中都创建副本,线程可访问自己内部的副本变量。该类提供了线程局部 (thread-local) 变量,访问这个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本
原理:每个线程都有一个ThreadLocalMap类型变量 threadLocals。ThreadLocal的set()会在threadLocals中保存以ThreadLocal对象为key,以保存的变量为value的值,get()会获取该值
建议:
- 将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露
- 每次使用完ThreadLocal,都调用它的remove()方法,清除数据。
2.ThreadLocal继承关系
3.源码走读
3.1.ThreadLocal.java
public class ThreadLocal<T> {
//**每一个实例都有一个唯一的threadLocalHashCode,值为上一个实例的值加上0x61c88647
//**作用是为了让哈希码能均匀的分布在2的N次方的数组里
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
//**返回此线程局部变量的当前线程的“初始值”
//**线程第一次使用get()方法时调用此方法,如果线程之前调用了set(T)方法,则不会对该线程再调用该方法
//**通常,此方法对每个线程最多调用一次,但调用了remove(),则会再次调用此方法
//**默认返回null,如果希望返回其它值,则须创建子类,并重写此方法,通常将使用匿名内部类完成此操作
protected T initialValue() {
return null;
}
//**在java8,使用函数式编程的方式设置并返回当前线程变量的初始值,与上个方法功能相同
//**示例:ThreadLocal<String> threadLocal = ThreadLocal.withInitial(() -> "test");
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
//**返回SuppliedThreadLocal对象,SuppliedThreadLocal是ThreadLocal的子类,
//**重写的initialValue方法调用supplier的get方法做为当前线程变量的初始值
return new SuppliedThreadLocal<>(supplier);
}
//**返回此线程局部变量的当前线程副本中的值,如果变量没有用于当前线程的值,则返回initialValue()的值
public T get() {
//**获取当前线程的实例
Thread t = Thread.currentThread();
//**获取当前线程中的ThreadLocalMap类型变量threadLocals
ThreadLocalMap map = getMap(t);
if (map != null) {
//**从threadLocals中获取以this为key的Entry对象
ThreadLocalMap.Entry e = map.getEntry(this);
//**如果Entry对象不为空,则返回它的value
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//**如果threadLocals对象不为空或者Entry为空,则调用setInitialValue进行初始化
return setInitialValue();
}
//**使用initialValue()的值初始化线程局部变量
private T setInitialValue() {
//**获取线程局部变量的初始值,默认为null
T value = initialValue();
//**获取当前线程的实例
Thread t = Thread.currentThread();
//**获取当前线程中的ThreadLocalMap类型变量threadLocals
ThreadLocalMap map = getMap(t);
//**如果threadLocals不为空,设置以this为key,以value为值的Entry对象
if (map != null)
map.set(this, value);
//**如果threadLocals为空,则进行初始化,并设置以this为key,以value为值的Entry对象
else
createMap(t, value);
return value;
}
//**设置线程局部变量的值
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//**移除此线程局部变量当前线程的值,如果随后调用get()方法,且没有调用set()设置值,则将调用initialValue()重新初始化值
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
//**从线程实例中获取threadLocals对象
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//**初始化线程t的threadLocals对象,并设置以this为key,以firstValue为值的Entry对象
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//**根据主线程中的ThreadLocalMap对象创建子线程的ThreadLocalMap对象
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
//**ThreadLocal对象不支持,在InheritableThreadLocal中实现
T childValue(T parentValue) {
throw new UnsupportedOperationException();
}
}
3.2.SuppliedThreadLocal.java
- ithInitial方法使用Supplier对象创建SuppliedThreadLocal对象
- 作用是为了在java8,支持使用函数式编程的方式设置并返回当前线程变量的初始值
static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<? extends T> supplier;
SuppliedThreadLocal(Supplier<? extends T> supplier) {
this.supplier = Objects.requireNonNull(supplier);
}
@Override
//**重写的initialValue方法,调用supplier的get方法做为当前线程变量的初始值
protected T initialValue() {
return supplier.get();
}
}
3.4.ThreadLocalMap.java
作用:
ThreadLocalMap是ThreadLocal的内部类。存放以ThreadLocal变量为key,以保存的变量为value的键值对
原理:
- ThreadLocalMap内部以Entry[]做为存储,原始长度默认为16,当元素个数达到扩容阀值(数组长度的3/4)-扩容阀值/4,则自动扩容,扩容到上次长度的2倍。Entry[]的长度必须是2的倍数
- Entry[]存储元素并不是按索引顺序存储,而是根据ThreadLocal进行计算存储位置,这样能实现根据ThreadLocal都能快速定位键值对,而不用遍历数组的每个元素
- 计算方法:ThreadLocal.threadLocalHashCode & (Entry[].length - 1)计算,ThreadLocal每一个实例都有一个唯一的threadLocalHashCode,值为上一个实例的值加上0x61c88647,该算法可以生成均匀的分布在2的N次方数组里的下标
- 如果计算的存储位置已经有元素,则会存放到下一个索引的位置,ThreadLocalMap会清理过期数据,并重新根据计算的存储位置重置,以保证尽可能减少和纠正此类问题
static class ThreadLocalMap {
//**存放单个键值对的对象
//**弱引用: 如果某个对象只有弱引用,那么gc会立即回收
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
//**默认初始化的大小,必须是2的倍数
private static final int INITIAL_CAPACITY = 16;
//**真正存储数据的数组,长度必须是2的倍数
private Entry[] table;
//**ThreadLocalMap的大小,即上述Entry[]中存放元素的个数
private int size = 0;
//**自动扩容的阀值
private int threshold; // Default to 0
//**设置自动扩容的阀值,为设定长度的2/3
private void setThreshold(int len) {
threshold = len * 2 / 3;
}
//**下一个索引
private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}
//**上一个索引
private static int prevIndex(int i, int len) {
return ((i - 1 >= 0) ? i - 1 : len - 1);
}
//**创建ThreadLocalMap,并设置第一个键值对
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
//**根据默认初始化的大小初始化Entry[]
table = new Entry[INITIAL_CAPACITY];
//**根据threadlocal对象的threadLocalHashCode和Entry[]数组的长度计算存放的位置
//**该算法可以生成均匀的分布在2的N次方数组里的下标
//**每个键值对并不是按顺序存放Entry[]里面
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
//**把Entry对象放到指定位置
table[i] = new Entry(firstKey, firstValue);
//**设置ThreadLocalMap的大小,即Entry[]中存放元素的个数
size = 1;
//**设置自动扩容的阀值
setThreshold(INITIAL_CAPACITY);
}
//**根据parentMap创建另一个parentMap,使用InheritableThreadLocal时,创建子线程时会调用
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
//**调用InheritableThreadLocal的childValue方法处理保存的对象
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
//**根据threadlocal获取Entry对象
private Entry getEntry(ThreadLocal<?> key) {
//**计算下标
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
//**如果对象存在,且key一样,则返回
if (e != null && e.get() == key)
return e;
else //**否则从指定索引的下一个索引开始查找
return getEntryAfterMiss(key, i, e);
}
//**没有直接命中,则指定索引的下一个索引开始查找
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
//**从指定索引开始遍历,直到数据为null
while (e != null) {
ThreadLocal<?> k = e.get();
//**如果数据存在则返回
if (k == key)
return e;
//**threadlocal对象为空,删除过期数据
if (k == null)
//**删除过期数据
expungeStaleEntry(i);
//**i为下一个索引
else
i = nextIndex(i, len);
//**e为下一个索引的值
e = tab[i];
}
//**没有数据不存在则返回null
return null;
}
//**根据threadlocal对象设置value
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
//**计算存放的索引
int i = key.threadLocalHashCode & (len-1);
//**从指定索引开始遍历Entry[],直到数据为null
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
//**如果数据存在,则直接返回
if (k == key) {
e.value = value;
return;
}
//**如果key为空,则替换当前索引的数据,并返回
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
//**设置指定索引的数据
tab[i] = new Entry(key, value);
int sz = ++size;
//**如果没有数据需要清理并且数组长度大于了扩容阀值,则扩容
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//**根据key删除数据
private void remove(ThreadLocal<?> key) {
Entry[] tab = table;
int len = tab.length;
//**计算存放的索引
int i = key.threadLocalHashCode & (len-1);
//**从指定的索引开始遍历Entry[],直到数据为null
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
//**如果指定key存在,则删除指定数据
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
//**替换指定索引的过期数据的
private void replaceStaleEntry(ThreadLocal<?> key, Object value, int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Entry e;
//**从指定索引往前找,找到过期数据的索引
int slotToExpunge = staleSlot;
for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null; i = prevIndex(i, len))
if (e.get() == null)
slotToExpunge = i;
//**从指定索引往后找
for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
//**如果是数据的key等于指定的key
if (k == key) {
//**替换它的value
e.value = value;
//**把它的位置和指定索引的位置互换(把数据替换到计算索引的位置)
tab[i] = tab[staleSlot];
tab[staleSlot] = e;
//**如果过期数据的的索引等于指定索引,则过期数据的索引为互换后的新索引
if (slotToExpunge == staleSlot)
slotToExpunge = i;
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
return;
}
//**过期数据的索引
if (k == null && slotToExpunge == staleSlot)
slotToExpunge = i;
}
//**如果指定数据不存在,则创建新的数据
tab[staleSlot].value = null;
tab[staleSlot] = new Entry(key, value);
//**如果有过时的条目,则清理
if (slotToExpunge != staleSlot)
cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
}
//**删除指定索引的过期数据,并返回数据为null的索引
private int expungeStaleEntry(int staleSlot) {
Entry[] tab = table;
int len = tab.length;
//**指定索引的数据置为null,数据减一(删除指定数据)
tab[staleSlot].value = null;
tab[staleSlot] = null;
size--;
Entry e;
int i;
//**从指定的索引的下一个数据开始循环遍历Entry[]数组,直到遇到null值
for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) {
ThreadLocal<?> k = e.get();
//**如果key为空,Entry置为空,数据减一(删除指定数据)
if (k == null) {
e.value = null;
tab[i] = null;
size--;
} else {
//**重新计算存放的索引
int h = k.threadLocalHashCode & (len - 1);
//**如果新索引不等于原索引,则原索引数据置为null
if (h != i) {
tab[i] = null;
//**如果新的存放的索引有数据,则存放到新索引的下一个索引,直到没有数据为止
while (tab[h] != null)
h = nextIndex(h, len);
tab[h] = e;
}
}
}
//**返回数据为null的索引
return i;
}
//**从指定索引开始清理数据
private boolean cleanSomeSlots(int i, int n) {
boolean removed = false;
Entry[] tab = table;
int len = tab.length;
do {
i = nextIndex(i, len);
Entry e = tab[i];
if (e != null && e.get() == null) {
n = len;
removed = true;
i = expungeStaleEntry(i);
}
} while ( (n >>>= 1) != 0);
return removed;
}
//**删除过期数据并扩容
private void rehash() {
//**删除所有的过期数据
expungeStaleEntries();
//**数据量 >= 扩容阀值 - 扩容阀值 / 4,则扩容
if (size >= threshold - threshold / 4)
resize();
}
//**扩容
private void resize() {
Entry[] oldTab = table;
int oldLen = oldTab.length;
//**扩容为原来的2倍
int newLen = oldLen * 2;
Entry[] newTab = new Entry[newLen];
int count = 0;
//**把旧数据存放在新的Entry[]中
for (int j = 0; j < oldLen; ++j) {
Entry e = oldTab[j];
if (e != null) {
ThreadLocal<?> k = e.get();
if (k == null) {
e.value = null; // Help the GC
} else {
int h = k.threadLocalHashCode & (newLen - 1);
while (newTab[h] != null)
h = nextIndex(h, newLen);
newTab[h] = e;
count++;
}
}
}
//**计算新的扩容阀值
setThreshold(newLen);
size = count;
table = newTab;
}
//**删除所有的过期数据
private void expungeStaleEntries() {
Entry[] tab = table;
int len = tab.length;
for (int j = 0; j < len; j++) {
Entry e = tab[j];
//**如果Entry不为空并且key为空(threadlocal对象为null)则为过期数据
if (e != null && e.get() == null)
expungeStaleEntry(j);
}
}
}
3.5 Thread 、ThreadLocal、ThreadLocalMap关系图
Thread1 和Thread2 线程中的ThreadLocal 是相同的话,那么ThreadLocalMap 中Entry 下标位置都是 ThreadLocal 的hashcode & (len-1)的位置如不出现hash冲突的话则都是相同的。
3.6 InheritThreadLocal详解
原理和解析:
- 每个线程都还有另外一个ThreadLocalMap类型变量inheritableThreadLocals
- InheritableThreadLocal重写了getMap和createMap方法,维护的不在是threadLocals,而是inheritableThreadLocals
- 当主线程创建一个子线程的时候,会判断主线程的inheritableThreadLocals是否为空
- 如果不为空,则会把inheritableThreadLocals的值传给子线程的inheritableThreadLocals,传送的逻辑是childValue实现的
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
...
//**获取主线程的实例
Thread parent = currentThread();
...
//**如果主线的inheritableThreadLocals不为空
if (parent.inheritableThreadLocals != null)
//**根据主线程的inheritableThreadLocals创建子线程的inheritableThreadLocals
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}
注意:
- 因为传送逻辑是在创建子线程的时候完成的,子线程创建后,主线程在修改InheritableThreadLocal变量的值,是无法传给子线程的
- 创建子线程完成后,原则上子线程和父线程中InheritableThreadLocal变量的值在没有关联,各自调用set/get/remove都只影响本线程中的值
- 如果InheritableThreadLocal变量的值是引用类型,通过get方法获取到对象后,直接修改了该对象的属性,则父线程和子线程都会受影响
InheritableThreadLocal类重写了ThreadLocal的3个函数:
/**
* 该函数在父线程创建子线程,向子线程复制InheritableThreadLocal变量时使用
*/
protected T childValue(T parentValue) {
return parentValue;
}
/**
* 由于重写了getMap,操作InheritableThreadLocal时,
* 将只影响Thread类中的inheritableThreadLocals变量,
* 与threadLocals变量不再有关系
*/
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**
* 类似于getMap,操作InheritableThreadLocal时,
* 将只影响Thread类中的inheritableThreadLocals变量,
* 与threadLocals变量不再有关系
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
线程间传值实现原理
public class Thread implements Runnable {
......(其他源码)
/*
* 当前线程的ThreadLocalMap,主要存储该线程自身的ThreadLocal
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal,自父线程集成而来的ThreadLocalMap,
* 主要用于父子线程间ThreadLocal变量的传递
* 本文主要讨论的就是这个ThreadLocalMap
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
......(其他源码)
}
Thread类中包含 threadLocals 和 inheritableThreadLocals 两个变量,其中inheritableThreadLocals 即主要存储可自动向子线程中传递的ThreadLocal.ThreadLocalMap。
接下来看一下父线程创建子线程的流程,我们从最简单的方式说起:
用户创建Thread
Thread thread = new Thread();
/**
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, gname)}, where {@code gname} is a newly generated
* name. Automatically generated names are of the form
* {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
* 默认情况下,设置inheritThreadLocals可传递
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
/**
* 初始化一个线程.
* 此函数有两处调用,
* 1、上面的 init(),不传AccessControlContext,inheritThreadLocals=true
* 2、传递AccessControlContext,inheritThreadLocals=false
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
......(其他代码)
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
......(其他代码)
}
可以看到,采用默认方式产生子线程时,inheritThreadLocals=true;若此时父线程inheritableThreadLocals不为空,则将父线程inheritableThreadLocals传递至子线程
ThreadLocal.createInheritedMap
让我们继续追踪createInheritedMap:
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
/**
* 构建一个包含所有parentMap中Inheritable ThreadLocals的ThreadLocalMap
* 该函数只被 createInheritedMap() 调用.
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
// ThreadLocalMap 使用 Entry[] table 存储ThreadLocal
table = new Entry[len];
// 逐一复制 parentMap 的记录
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
// 可能会有同学好奇此处为何使用childValue,而不是直接赋值,
// 毕竟childValue内部也是直接将e.value返回;
// 个人理解,主要为了减轻阅读代码的难度
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
从ThreadLocalMap可知,子线程将parentMap中的所有记录逐一复制至自身线程
InheritableThreadLocal主要用于子线程创建时,需要自动继承父线程的ThreadLocal变量,方便必要信息的进一步传递。
public class Test {
private static List getList(String param) {
List rst = new ArrayList<>();
rst.add(param);
return rst;
}
private static final InheritableThreadLocal<List> threadLocal = new InheritableThreadLocal<>();
public static void test(Consumer<InheritableThreadLocal<List>> consumer) throws InterruptedException {
threadLocal.set(getList("test"));
Thread child = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()){
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("子线程中threadLocal的值:" + threadLocal.get());
}
});
System.out.println("主线程中threadLocal的值:" + threadLocal.get());
child.start();
TimeUnit.MILLISECONDS.sleep(1);
consumer.accept(threadLocal);
System.out.println("主线程中threadLocal的值:" + threadLocal.get());
TimeUnit.MILLISECONDS.sleep(3);
child.interrupt();
}
public static void main(String[] args) throws InterruptedException {
//**创建子线程完成后,主线程调用set方法修改值,不会影响到子线程
test(local -> local.set(getList("test1")));
System.out.println("===========================");
//**保存list对象时,通过get方法获取,然后修改list的值,则会影响到子线程
test(local -> local.get().set(0, "test2"));
}
}
//**执行结果
主线程中threadLocal的值:[test]
子线程中threadLocal的值:[test]
主线程中threadLocal的值:[test1]
子线程中threadLocal的值:[test]
===========================
主线程中threadLocal的值:[test]
子线程中threadLocal的值:[test]
主线程中threadLocal的值:[test2]
子线程中threadLocal的值:[test2]
3.7 TransmittableThreadLocal详解
用于解决使用线程池缓存线程的组件的情况下传递ThreadLocal
使用场景:分布式跟踪系统,应用容器或上下层框架跨应用代码给下层SDK传递信息,日志收集系统上下文,
源码分析:
TransmittableThreadLocal 继承自 InheritableThreadLocal,这样可以在不破坏ThreadLocal 本身的情况下,使得当用户利用 new Thread() 创建线程时仍然可以达到传递InheritableThreadLocal 的目的。
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T>{......}
TransmittableThreadLocal相比于InheritableThreadLocal比较关键的一点是引入了holder变量,这样就不必对外暴露Thread中的inherittablethreadlocals变量保存ThreadLocalMap的封装性
// 理解holder,需注意如下几点:
// 1、holder 是 InheritableThreadLocal 变量;
// 2、holder 是 static 变量;
// 3、value 是 WeakHashMap;
// 4、深刻理解 ThreadLocal 工作原理;
private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
@Override
protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
return new WeakHashMap<>();
}
@Override
protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
return new WeakHashMap<>(parentValue);
}
};
// 调用 get() 方法时,同时将 this 指针放入 holder
public final T get() {
T value = super.get();
if (null != value) {
addValue();
}
return value;
}
void addValue() {
if (!holder.get().containsKey(this)) {
holder.get().put(this, null); // WeakHashMap supports null value.
}
}
// 调用 set() 方法时,同时处理 holder 中 this 指针
public final void set(T value) {
super.set(value);
if (null == value) { // may set null to remove value
removeValue();
} else {
addValue();
}
}
void removeValue() {
holder.get().remove(this);
}