一、干嘛的?
将threadlocal传递给线程池中的线程。
二、怎么使用?
使用TtlRunnable
和TtlCallable
来修饰传入线程池的Runnable
和Callable
。
示例代码:
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程中设置
context.set("value-set-in-parent");
Runnable task = new RunnableTask();
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
// =====================================================
// Task中可以读取,值是"value-set-in-parent"
String value = context.get();
上面演示了Runnable
,Callable
的处理类似
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程中设置
context.set("value-set-in-parent");
Callable call = new CallableTask();
// 额外的处理,生成修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
// =====================================================
// Call中可以读取,值是"value-set-in-parent"
String value = context.get();
三、核心源码实现?
从上面的Runnable的示例代码出发,我们来看一下TransmittableThreadLocal的实现。
3.1 TransmittableThreadLocal context = new TransmittableThreadLocal<>();
首先看一下TransmittableThreadLocal类的签名:
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> implements TtlCopier<T>
从以上类的签名,我们看到TransmittableThreadLocal继承自InheritableThreadLocal,而InheritableThreadLocal上一篇文章已经捋了过了,已经很熟了,不在赘述。 我们接着来看一下TtlCopier:
@FunctionalInterface
public interface TtlCopier<T> {
T copy(T parentValue);
}
如上我们看到TtlCopier是一个函数式的接口。
示例代码第一行,调用了TransmittableThreadLocal的构造函数,因此我们看一下TransmittableThreadLocal的构造函数有什么?
public TransmittableThreadLocal() {
this(false);
}
public TransmittableThreadLocal(boolean disableIgnoreNullValueSemantics) {
this.disableIgnoreNullValueSemantics = disableIgnoreNullValueSemantics;
}
private final boolean disableIgnoreNullValueSemantics;
如上我们看到只是一个简单的构造函数,无他。
3.2 context.set("value-set-in-parent");
接着看一下示例代码的第二行:context.set("value-set-in-parent");
因此我们来看一下TransmittableThreadLocal的set方法做了什么?
@Override
public final void set(T value) {
if (!disableIgnoreNullValueSemantics && null == value) {
// may set null to remove value
remove();
} else {
super.set(value);
addThisToHolder();
}
}
如果disableIgnoreNullValueSemantics == false 且null == value则remove(),
否则的则 super.set(value); - > addThisToHolder();
super.set(value); 这个我们很熟了不在赘述,现在看一下addThisToHolder();做了啥?
@SuppressWarnings("unchecked")
private void addThisToHolder() {
if (!holder.get().containsKey(this)) {
holder.get().put((TransmittableThreadLocal<Object>) this, null); // WeakHashMap supports null value.
}
}
看到一个变量holder,看一下这个是什么?
private static final InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>> holder =
new InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>() {
@Override
protected WeakHashMap<TransmittableThreadLocal<Object>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<Object>, Object>();
}
@Override
protected WeakHashMap<TransmittableThreadLocal<Object>, ?> childValue(WeakHashMap<TransmittableThreadLocal<Object>, ?> parentValue) {
return new WeakHashMap<TransmittableThreadLocal<Object>, Object>(parentValue);
}
};
如上我们看到holder是一个static的InheritableThreadLocal的变量,然后这个InheritableThreadLocal存的是WeakHashMap,然后这个WeakHashMap,key是TransmittableThreadLocal,value是Object。
然后我看到它的childValue方法,说明这个InheritableThreadLocal如果往子线程中传递化,它的value是重新new出来的,而不只是传递引用。
addThisToHolder
holder.get() 会返回当前线程中的
ThreadLocal.ThreadLocalMap inheritableThreadLocals变量中存储的WeakHashMap,如果 WeakHashMap不存在依照上面的:
@Override
protected WeakHashMap<TransmittableThreadLocal<Object>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<Object>, Object>();
}
则会被创建一个出来,如果WeakHashMap不包含当前这个TransmittableThreadLocal,则会将当前这个TransmittableThreadLocal,put到WeakHashMap中,value则为null。
总结一下addThisToHolder到底是干嘛的?
顾名思义:将这个TransmittableThreadLocal 加到holder中。也就是说通过holder我们可以找到java进程中所有的TransmittableThreadLocal。
首先存在一个全局的holder这个holder也是一个InheritableThreadLocal,它维护了一个WeakHashMap,这个WeakHashMap用于收集线程中所有的TransmittableThreadLocal。
内存结构如下图1所示:
ps:这里简要说明一下:ThreadLocal.ThreadLocalMap和WeakHashMap中的区别?ThreadLocalMap是一个用移位解决hash冲突的简易map,WeakHashMap是一个用链表解决hash冲突的简易map;
相同点ThreadLocalMap.Entry和WeakHashMap都继承弱引用,弱引用的reference都指向key; ThreadLocalMap.Entry:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
WeakHashMap.Entry:
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
接下来我们在回到TransmittableThreadLocal的set方法中,接着看一下remove()方法做了什么?
@Override
public final void remove() {
removeThisFromHolder();
super.remove();
}
super.remove();我们不看了,都很熟了。 所以接着跟一下removeThisFromHolder();
private void removeThisFromHolder() {
holder.get().remove(this);
}
如上我们看到从holder中拿出当前线程中的WeakHashMap,将WeakHashMap对应的TransmittableThreadLocal删掉。
至此,TransmittableThreadLocal的set方法我们已经全部都跟完了,再次总结下set方法到底做了什么?
首先如果disableIgnoreNullValueSemantics是false(默认就是false),且value = null,则此时会调用InheritableThreadLocal的remove方法,将对应Entry删掉,
否则的话,就会调用InheritableThreadLocal的set方法;然后不管是remove还是set,做完之后,都还需要对holder进行维护,因为holder这个变量是用来记录,当前这个线程的 ThreadLocal.ThreadLocalMap inheritableThreadLocals变量,有哪些TransmittableThreadLocal。如图1所示非常直观。
3.3 Runnable ttlRunnable = TtlRunnable.get(task);
首先看一下TtlRunnable的签名,看一下get方法; TtlRunnable的签名和成员变量如下:
public final class TtlRunnable implements Runnable, TtlWrapper<Runnable>, TtlEnhanced, TtlAttachments {
private final AtomicReference<Object> capturedRef;
private final Runnable runnable;
private final boolean releaseTtlValueReferenceAfterRun;
接着跟一下它实现的接口:
首先TtlEnhanced:
public interface TtlEnhanced {
}
是空的,为空的接口的作用,一般来说是为了给其他的类打标签;
看一下TtlAttachments:
public interface TtlAttachments extends TtlEnhanced {
void setTtlAttachment(@NonNull String key, Object value);
<T> T getTtlAttachment(@NonNull String key);
String KEY_IS_AUTO_WRAPPER = "ttl.is.auto.wrapper";
}
不知道是干嘛的,接着看TtlWrapper:
public interface TtlWrapper<T> extends TtlEnhanced {
/**
* unwrap {@link TtlWrapper} to the original/underneath one.
*
* @see TtlUnwrap#unwrap(Object)
*/
@NonNull
T unwrap();
}
也不知道是干嘛的?看一下TtlRunnable中对它实现:
@NonNull
@Override
public Runnable unwrap() {
return runnable;
}
知道这个接口是干嘛的了,用来返回装饰者装饰的是谁。并且根据注释知道是返回最原始的被装饰者。
好,接着看一下它的static get是干嘛的?
@Nullable
public static TtlRunnable get(@Nullable Runnable runnable) {
return get(runnable, false, false);
}
继续跟:
/**
* Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.
*
* @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}.
* @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.
* @param idempotent is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable},
* otherwise throw {@link IllegalStateException}.
* <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.
* @return Wrapped {@link Runnable}
* @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent.
*/
@Nullable
public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {
if (null == runnable) return null;
if (runnable instanceof TtlEnhanced) {
// avoid redundant decoration, and ensure idempotency
if (idempotent) return (TtlRunnable) runnable;
else throw new IllegalStateException("Already TtlRunnable!");
}
return new TtlRunnable(runnable, releaseTtlValueReferenceAfterRun);
}
如果入参的runnable已经是TtlEnhanced的实例了,那么如果是idempotent(中文含义幂等)则直接将入参runnable返回,否则则抛出异常。
接着跟:
private TtlRunnable(@NonNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
this.capturedRef = new AtomicReference<Object>(capture());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
接下来跟capture():
public static class Transmitter {
/**
* Capture all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread.
*
* @return the captured {@link TransmittableThreadLocal} values
* @since 2.3.0
*/
@NonNull
public static Object capture() {
return new Snapshot(captureTtlValues(), captureThreadLocalValues());
}
如上Transmitter是TransmittableThreadLocal的static内部类:
接着跟:
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#captureTtlValues
private static HashMap<TransmittableThreadLocal<Object>, Object> captureTtlValues() {
HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value = new HashMap<TransmittableThreadLocal<Object>, Object>();
for (TransmittableThreadLocal<Object> threadLocal : holder.get().keySet()) {
ttl2Value.put(threadLocal, threadLocal.copyValue());
}
return ttl2Value;
}
跟一下这个:threadLocal.copyValue();com.alibaba.ttl.TransmittableThreadLocal#copyValue
private T copyValue() {
return copy(get());
}
com.alibaba.ttl.TransmittableThreadLocal#copy:
public T copy(T parentValue) {
return parentValue;
}
com.alibaba.ttl.TransmittableThreadLocal#get:
@Override
public final T get() {
T value = super.get();
if (disableIgnoreNullValueSemantics || null != value) addThisToHolder();
return value;
}
至此我们看到了TransmittableThreadLocal中的get()的方法实现了,也是调用父类InheritableThreadLocal中的get方法,同时对holder进行维护,
captureTtlValues是干嘛的呢?
captureTtlValues就是将当前线程中的所有的TransmittableThreadLocal全部拿出来,同时构建成一个map返回,key为TransmittableThreadLocal,value为TransmittableThreadLocal在当前线程的value,并且这个value只是引用传递。
接下来跟:com.alibaba.ttl.TransmittableThreadLocal.Transmitter#captureThreadLocalValues
private static HashMap<ThreadLocal<Object>, Object> captureThreadLocalValues() {
final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = new HashMap<ThreadLocal<Object>, Object>();
for (Map.Entry<ThreadLocal<Object>, TtlCopier<Object>> entry : threadLocalHolder.entrySet()) {
final ThreadLocal<Object> threadLocal = entry.getKey();
final TtlCopier<Object> copier = entry.getValue();
threadLocal2Value.put(threadLocal, copier.copy(threadLocal.get()));
}
return threadLocal2Value;
}
如上我们看到captureThreadLocalValues和captureTtlValues做了基本上一样的事情,只是作用的对象是threadLocalHolder,因此我们看一下这个threadLocalHolder是个啥?
private static volatile WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> threadLocalHolder = new WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>>();
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#threadLocalHolder是一个WeakHashMap,key为ThreadLocal value为TtlCopier。
接着跟什么时候写threadLocalHolder:
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#registerThreadLocal(java.lang.ThreadLocal, com.alibaba.ttl.TtlCopier, boolean)
和com.alibaba.ttl.TransmittableThreadLocal.Transmitter#unregisterThreadLocal
/**
* Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances
* to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.
* <p>
* If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.
* since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,
* it is unnecessary to register a {@link TransmittableThreadLocal} instance.
*
* <B><I>Caution:</I></B><br>
* If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},
* the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!
*
* @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability
* @param copier the {@link TtlCopier}
* @param force if {@code true}, update {@code copier} to {@link ThreadLocal} instance
* when a {@link ThreadLocal} instance is already registered; otherwise, ignore.
* @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false}
* @see #registerThreadLocal(ThreadLocal, TtlCopier)
* @since 2.11.0
*/
@SuppressWarnings("unchecked")
public static <T> boolean registerThreadLocal(@NonNull ThreadLocal<T> threadLocal, @NonNull TtlCopier<T> copier, boolean force) {
if (threadLocal instanceof TransmittableThreadLocal) {
logger.warning("register a TransmittableThreadLocal instance, this is unnecessary!");
return true;
}
synchronized (threadLocalHolderUpdateLock) {
if (!force && threadLocalHolder.containsKey(threadLocal)) return false;
WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> newHolder = new WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>>(threadLocalHolder);
newHolder.put((ThreadLocal<Object>) threadLocal, (TtlCopier<Object>) copier);
threadLocalHolder = newHolder;
return true;
}
}
public static <T> boolean unregisterThreadLocal(@NonNull ThreadLocal<T> threadLocal) {
if (threadLocal instanceof TransmittableThreadLocal) {
logger.warning("unregister a TransmittableThreadLocal instance, this is unnecessary!");
return true;
}
synchronized (threadLocalHolderUpdateLock) {
if (!threadLocalHolder.containsKey(threadLocal)) return false;
WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> newHolder = new WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>>(threadLocalHolder);
newHolder.remove(threadLocal);
threadLocalHolder = newHolder;
return true;
}
}
如上,我们根据注释知道,threadLocalHolder是用来注册老代码中已经存在的ThreadLocal和InheritableThreadLocal的,用来增强TransmittableThreadLocal的能力的。
因此:captureThreadLocalValues可以获得threadLocalHolder中保存的ThreadLocal(包括InheritableThreadLocal),以及他们在当前线程中的value;
接着跟:new Snapshot(captureTtlValues(), captureThreadLocalValues());
com.alibaba.ttl.TransmittableThreadLocal.Transmitter.Snapshot
private static class Snapshot {
final HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value;
final HashMap<ThreadLocal<Object>, Object> threadLocal2Value;
private Snapshot(HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value, HashMap<ThreadLocal<Object>, Object> threadLocal2Value) {
this.ttl2Value = ttl2Value;
this.threadLocal2Value = threadLocal2Value;
}
}
接着跟:this.capturedRef = new AtomicReference(capture());
public AtomicReference(V initialValue) {
value = initialValue;
}
至此我们看到了TtlRunnable中的AtomicReference capturedRef; 的value字段指向的Snapshot对象,而Snapshot保存的是,当前线程中所有的TransmittableThreadLocal和ThreadLocal(包括InheritableThreadLocal)以及他们在当前线程中的值。
接着跟,因为之后TtlRunnable就提交到线程池中了,因此就要看一下这个TtlRunnable的run方法了:
@Override
public void run() {
final Object captured = capturedRef.get();
if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {
throw new IllegalStateException("TTL value reference is released after run!");
}
final Object backup = replay(captured);
try {
runnable.run();
} finally {
restore(backup);
}
}
如上如果captured == null则抛异常,如果 != null && releaseTtlValueReferenceAfterRun == true 则需要执行
capturedRef.compareAndSet(captured, null),利用cas将AtomicReference中的value设置为null,这里提出一个问题,为什么这里要有AtomicReference?
cas失败,则抛出异常;
接下来跟:
final Object backup = replay(captured);和restore(backup); 从字面上理解replay是重放的意思,也就是说将父线程中的threadlocal的value给放到现在这个线程,因此此时已经是进入线程池中的线程中了,在
runnable.run();执行完之后,执行的restore(backup); 从字面理解是归还的意思,也就是需要将replay放进去的Entry再删掉。接下来我们来跟一下代码,看看我们的猜测对不对。
@NonNull
public static Object replay(@NonNull Object captured) {
final Snapshot capturedSnapshot = (Snapshot) captured;
return new Snapshot(replayTtlValues(capturedSnapshot.ttl2Value), replayThreadLocalValues(capturedSnapshot.threadLocal2Value));
}
@NonNull
private static HashMap<TransmittableThreadLocal<Object>, Object> replayTtlValues(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> captured) {
HashMap<TransmittableThreadLocal<Object>, Object> backup = new HashMap<TransmittableThreadLocal<Object>, Object>();
for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {
TransmittableThreadLocal<Object> threadLocal = iterator.next();
// backup
backup.put(threadLocal, threadLocal.get());
// clear the TTL values that is not in captured
// avoid the extra TTL values after replay when run task
if (!captured.containsKey(threadLocal)) {
iterator.remove();
threadLocal.superRemove();
}
}
// set TTL values to captured
setTtlValuesTo(captured);
// call beforeExecute callback
doExecuteCallback(true);
return backup;
}
replayTtlValues首先是遍历当前池化线程中的所有TransmittableThreadLocal的将他们先保存起来放到
HashMap<TransmittableThreadLocal, Object> backup里面;
之后如果当前池化线程中的TransmittableThreadLocal有不在 “父线程(也就是投放runnable的那个线程)的所有TransmittableThreadLocal”中的,则该TransmittableThreadLocal会被从池化线程中删掉,同时维护holder,也就是将其从holder中也删掉。
然后调用:
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#setTtlValuesTo
private static void setTtlValuesTo(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> ttlValues) {
for (Map.Entry<TransmittableThreadLocal<Object>, Object> entry : ttlValues.entrySet()) {
TransmittableThreadLocal<Object> threadLocal = entry.getKey();
threadLocal.set(entry.getValue());
}
}
如上我们看到,将父线程中的value,设置到了当前线程中了;
之后:
// call beforeExecute callback
doExecuteCallback(true);
看注释知道是调用回调函数:com.alibaba.ttl.TransmittableThreadLocal#doExecuteCallback
private static void doExecuteCallback(boolean isBefore) {
for (TransmittableThreadLocal<Object> threadLocal : holder.get().keySet()) {
try {
if (isBefore) threadLocal.beforeExecute();
else threadLocal.afterExecute();
} catch (Throwable t) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "TTL exception when " + (isBefore ? "beforeExecute" : "afterExecute") + ", cause: " + t.toString(), t);
}
}
}
}
对于当前池化线程中的所有TransmittableThreadLocal,串行调用他们的beforeExecute()方法,当前
com.alibaba.ttl.TransmittableThreadLocal#beforeExecute为空;
protected void beforeExecute() {
}
接着跟:
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#replayThreadLocalValues
private static HashMap<ThreadLocal<Object>, Object> replayThreadLocalValues(@NonNull HashMap<ThreadLocal<Object>, Object> captured) {
final HashMap<ThreadLocal<Object>, Object> backup = new HashMap<ThreadLocal<Object>, Object>();
for (Map.Entry<ThreadLocal<Object>, Object> entry : captured.entrySet()) {
final ThreadLocal<Object> threadLocal = entry.getKey();
backup.put(threadLocal, threadLocal.get());
final Object value = entry.getValue();
if (value == threadLocalClearMark) threadLocal.remove();
else threadLocal.set(value);
}
return backup;
}
如上,我们看到首先遍历父线程中的ThreadLocal的将其,以及他们在池化线程中的value先保存下来放到backup中,之后如果将在父线程中的捕获到的value,设置到当前的池化线程中,如果value=
private static final Object threadLocalClearMark = new Object();则将改threadLocal在池化线程中删掉。这个threadLocalClearMark先存疑,我们先接着往下跟,
因此:
final Object backup = replay(captured);
这个backup是一个Snapshot保存的是,池化线程在执行run方法前,存在的TransmittableThreadLocal和ThreadLocal已经他们的value;
下来执行的是
runnable.run();
那么在runnable中对TransmittableThreadLocal和已经注册的ThreadLocal调用其get方法,能拿到他们父线程中的值,就顺其自然了,因为已经重放到池化线程中的了。
接着执行的是:
restore(backup);
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#restore
public static void restore(@NonNull Object backup) {
final Snapshot backupSnapshot = (Snapshot) backup;
restoreTtlValues(backupSnapshot.ttl2Value);
restoreThreadLocalValues(backupSnapshot.threadLocal2Value);
}
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#restoreTtlValues
private static void restoreTtlValues(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> backup) {
// call afterExecute callback
doExecuteCallback(false);
for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {
TransmittableThreadLocal<Object> threadLocal = iterator.next();
// clear the TTL values that is not in backup
// avoid the extra TTL values after restore
if (!backup.containsKey(threadLocal)) {
iterator.remove();
threadLocal.superRemove();
}
}
// restore TTL values
setTtlValuesTo(backup);
}
先对所有的TransmittableThreadLocal执行回调函数:
protected void afterExecute() {
}
遍历池化线程中的所有的TransmittableThreadLocal,如果不在backup中的,则将其删除,将holder中的也删除,
之后调用
// restore TTL values
setTtlValuesTo(backup);
将原来池化线程中的TransmittableThreadLocal的value在set到池化线程中;
接着跟一下:
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#restoreThreadLocalValues
private static void restoreThreadLocalValues(@NonNull HashMap<ThreadLocal<Object>, Object> backup) {
for (Map.Entry<ThreadLocal<Object>, Object> entry : backup.entrySet()) {
final ThreadLocal<Object> threadLocal = entry.getKey();
threadLocal.set(entry.getValue());
}
}
将原先在池化线程中的threadlocal的value在恢复回去;
至此:TransmittableThreadLocal的源码我们就跟完了,于是总结一下:
3.4 总结
首先是用TtlRunnable去修饰Runnable,在new TtlRunnable的时候,会去capture捕获当前父线程的TransmittableThreadLocal和已注册的ThreadLocal,及其value,
然后在runnable运行之前回去执行replay回放,也就是从父线程捕获到的父线程的TransmittableThreadLocal和已注册的ThreadLocal,及其value,放置到池化线程中,使得池化线程中的
ThreadLocal.ThreadLocalMap inheritableThreadLocals和破获到的一样,同时将池化线程中原来所具有的TransmittableThreadLocal和已注册的ThreadLocal,及其value,保存起来,
在执行完run方法后,在将其恢复restore,因此restore是恢复的意思。
1、capture
2、replay and backup
3、run
4、restore
3.5 QA
3.5.1 如果不维护holder那个数据结构可以吗?
答:不可以!holder是一个InheritableThreadLocal,它维护了一个WeakHashMap,这个WeakHashMap用于收集线程中所有的TransmittableThreadLocal。那就是说如果没有这个holder我们能收集到吗?
如果我们能拿到Thread中的ThreadLocal.ThreadLocalMap inheritableThreadLocals,然后对其做遍历就行,但是ThreadLocalMap是包可见性,因此在应用代码中是拿不到的,所以holder只能必须存在。
3.5.2 holder中如果不用WeakHashMap可以吗?
答案:不可以!因为如果某个TransmittableThreadLocal已经强不可以达,那么此时Thread的ThreadLocal.ThreadLocalMap inheritableThreadLocals是有机制可以保证相应的Entry被删掉的,
可以导致对应的TransmittableThreadLocal 和 它的value被gc掉的,如果此时不用WeakHashMap而用HashMap,那么则该TransmittableThreadLocal会永远强可达;
3.5.3 为什么com.alibaba.ttl.TtlRunnable#capturedRef要用AtomicReference类型,不用可以吗?
答案:不可以!如果com.alibaba.ttl.TtlRunnable#releaseTtlValueReferenceAfterRun为true的话,也就是说应该在TtlRunnable执行完之后就清掉父线程的快照的话,那么这个时候这个
TtlRunnable是不可以同时提交给两个线程去执行的,如果这个使用不用AtomicReference,而是让TtlRunnable#capturedRef直接指向快照Snapshot,那么如果
应用程序同时将这个TtlRunnable让两个线程去执行,那么如果上边用红框画出来的代码,没有采用cas,只是简单的执行,capturedRef=null,
那么那就会导致这个TtlRunnable可以在两个线程中,同时执行而且不会有问题,但是我们将releaseTtlValueReferenceAfterRun设置为true就是为了让一个TtlRunnable只能跑一次,于是就语义冲突了,
然后如果是用AtomicReference做cas的话 ,则可以避免,因为,只是上诉红框中的代码同时跑的话,必会有一个线程是cas失败,于是就抛出异常了,保证了一个TtlRunnable只能跑一次,这个语义。
3.5.4 threadLocalClearMark 这个变量在什么地方用的?
com.alibaba.ttl.TransmittableThreadLocal.Transmitter#clear
代码如下:
/**
* Clear all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread,
* and return the backup {@link TransmittableThreadLocal} values in the current thread before clear.
*
* @return the backup {@link TransmittableThreadLocal} values before clear
* @since 2.9.0
*/
@NonNull
public static Object clear() {
final HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value = new HashMap<TransmittableThreadLocal<Object>, Object>();
final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = new HashMap<ThreadLocal<Object>, Object>();
for (Map.Entry<ThreadLocal<Object>, TtlCopier<Object>> entry : threadLocalHolder.entrySet()) {
final ThreadLocal<Object> threadLocal = entry.getKey();
threadLocal2Value.put(threadLocal, threadLocalClearMark);
}
return replay(new Snapshot(ttl2Value, threadLocal2Value));
}
如上代码:删掉当前线程的ThreadLocal.ThreadLocalMap inheritableThreadLocals中的所有TransmittableThreadLocal的Entry,
并且将当前线程中的所有的ThreadLocal对应的value,都设置为
threadLocalClearMark。父线程中的ThreadLocal对应的value如果是threadLocalClearMark,则池化线程中的就不需要有这个Threadlocal。