1,、簡介
TransmittableThreadLocal 是Alibaba開源的、用于解決 “在使用線程池等會緩存線程的組件情況下傳遞ThreadLocal” 問題的 InheritableThreadLocal 擴(kuò)展,。若希望 TransmittableThreadLocal 在線程池與主線程間傳遞,,需配合 TtlRunnable 和 TtlCallable 使用。
2,、使用場景
下面是幾個典型場景例子,。
- 分布式跟蹤系統(tǒng)
- 應(yīng)用容器或上層框架跨應(yīng)用代碼給下層SDK傳遞信息
- 日志收集記錄系統(tǒng)上下文
3、源碼分析
TransmittableThreadLocal 繼承自 InheritableThreadLocal,,這樣可以在不破壞ThreadLocal 本身的情況下,,使得當(dāng)用戶利用 new Thread() 創(chuàng)建線程時仍然可以達(dá)到傳遞InheritableThreadLocal 的目的。
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> { ...... }
TransmittableThreadLocal 相比較 InheritableThreadLocal 很關(guān)鍵的一點(diǎn)改進(jìn)是引入holder變量,,這樣就不必對外暴露Thread中的 inheritableThreadLocals(參考InheritableThreadLocal詳解),,保持ThreadLocal.ThreadLocalMap的封裝性。
// 理解holder,,需注意如下幾點(diǎn):
// 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);
}
};
個人認(rèn)為 holder 變量的設(shè)計(jì),,極大體現(xiàn)了作者的智慧,,讓人無數(shù)次獻(xiàn)上膝蓋。,。,。
// 調(diào)用 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.
}
}
// 調(diào)用 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);
}
4,、工作流程簡介
自定義 TtlRunnable 實(shí)現(xiàn) Runnable,TtlRunnable初始化方法中保持當(dāng)前線程中已有的TransmittableThreadLocal
private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
this.copiedRef = new AtomicReference<Map<TransmittableThreadLocal<?>, Object>>(TransmittableThreadLocal.copy());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
線程池中線程 調(diào)用run方法,,執(zhí)行前先backup holder中所有的TransmittableThreadLocal,, copiedRef中不存在,holder存在的,,說明是后來加進(jìn)去的,,remove掉holder中的,;將copied中的TransmittableThreadLocal set到當(dāng)前線程中
public void run() {
Map<TransmittableThreadLocal<?>, Object> copied = copiedRef.get();
if (copied == null || releaseTtlValueReferenceAfterRun && !copiedRef.compareAndSet(copied, null)) {
throw new IllegalStateException("TTL value reference is released after run!");
}
Map<TransmittableThreadLocal<?>, Object> backup = TransmittableThreadLocal.backupAndSetToCopied(copied);
try {
runnable.run();
} finally {
TransmittableThreadLocal.restoreBackup(backup);
}
}
執(zhí)行后再恢復(fù) backup 的數(shù)據(jù)到 holder 中(backup中不存在,holder中存在的TransmittableThreadLocal,,從holder中remove掉),,將 backup 中的 TransmittableThreadLocal set到當(dāng)前線程中
5、參考文獻(xiàn)
- transmittable-thread-local
|