transmittable-thread-local源码梳理

1,167 阅读13分钟

一、干嘛的?

将threadlocal传递给线程池中的线程。

二、怎么使用?

使用TtlRunnableTtlCallable来修饰传入线程池的RunnableCallable

示例代码:

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();

上面演示了RunnableCallable的处理类似

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所示:

image.png 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,那么如果

image.png 应用程序同时将这个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。