使用Transmittable-Thread-Local作为线程上下文传递解决方案

  • Java
  • ThreadLocal
大约 2 分钟

使用Transmittable-Thread-Local作为线程上下文传递解决方案

TransmittableThreadLocal 是阿里开源的线程上下文传递解决方案,提供了一种增强的 InheritableThreadLocal,使得线程池等组件可以正确处理线程内数据,避免并发问题。

TransmittableThreadLocal (TTL), the missing Java™ std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.

前置知识

ThreadLocal

ThreadLocal 是一个线程内部存储类,通过它可以在指定的线程中存储数据,对不同的线程的数据进行隔离,让每个线程可以访问自己内部的 ThreadLocal 存储的数据。

每个Thread对象拥有一个ThreadLocalMap对象,这个ThreadLocalMap对象是ThreadLocal的内部类,它实现了Map接口,主要作用是存储K-V键值对,key就是ThreadLocal对象,value就是我们通过set方法存储的对象。

在线程中如果我们尝试获取其他线程的ThreadLocal对象,这个get方法会根据Thread.currentThread()获取当前线程,然后通过当前线程的ThreadLocalMap对象获取ThreadLocal对象,最后返回ThreadLocal对象对应的value。所以是无法获取其他线程的ThreadLocal对象的。

InheritableThreadLocal

InheritableThreadLocal 继承 ThreadLocal,并重写了 set、get、initialValue 方法。

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
  /**
  * 设置线程的ThreadLocalMap
  */
  protected void setThreadLocalMap(ThreadLocalMap map) {
    threadLocals = map;
  }

  /**
  * 获取线程的ThreadLocalMap
  */
  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")
        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;
  }

  /**
  * 创建ThreadLocalMap
  */
  void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
  }

  /**
  * 获取线程的ThreadLocalMap
  */
  ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
  }
}

Thread类中有两个ThreadLocalMap类型的成员变量threadLocals和inheritableThreadLocals

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

如果是在父线程中创建的子线程,那么子线程会继承父线程的inheritableThreadLocals,如果子线程中没有设置inheritableThreadLocals,那么子线程会继承父线程的threadLocals。

但是在实际应用场景中,我们基本上都是使用线程池,线程池使用线程复用的技术,而inheritableThreadLocals是在创建子线程的时候设置的,所以在这种场景下inheritableThreadLocals就失去了意义。

上次编辑于: