并发编程(四)-InheritableThreadLocal 源码分析

一、InheritableThreadLocal 是什么?


InheritableThreadLocal 是 Java 中的一个类,它是 ThreadLocal 类的一个子类。与 ThreadLocal 不同的是,InheritableThreadLocal 可以在父线程和子线程之间共享数据,子线程可以继承父线程的 InheritableThreadLocal 变量的值。这意味着,当一个线程创建了一个子线程时,子线程可以访问父线程中的 InheritableThreadLocal 变量的值,而不是创建一个新的变量。这种机制可以使得在多个线程之间共享数据变得更加方便。

注意:InheritableThreadLocal 本身并不提供线程安全的保证,因为它只是提供了一种在多线程之间共享数据的机制,而不涉及数据的同步。因此,在使用 InheritableThreadLocal 时,需要自己保证线程安全。可以通过以下方法保证线程安全:

  • 将InheritableThreadLocal 对象的访问范围限制在单个线程中,避免多个线程同时访问同一个对象。

  • 对于需要跨线程共享的变量,使用线程安全的方式来访问。可以使用synchronized 关键字或者使用java.util.concurrent包中的线程安全类。

另外,需要注意的是,当 InheritableThreadLocal 变量被使用时,需要及时地清理它的值,避免出现内存泄漏的情况。

二、InheritableThreadLocal 使用场景


InheritableThreadLocal 主要用于需要在线程之间共享数据,并且希望子线程能够继承父线程的数据的场景。

  • 在 Web 应用程序中,将用户信息存储在 InheritableThreadLocal 变量中,这样在处理用户请求的过程中,不同的线程都可以访问到用户信息,而且在子线程中也可以继承父线程的用户信息,从而避免了在不同的线程中反复传递用户信息的麻烦。

  • InheritableThreadLocal 也可以用于在框架中传递上下文信息,比如在分布式系统中,将请求的 trace id 存储在 InheritableThreadLocal 中,从而在整个请求链路中都能够方便地获取到 trace id。

总之,InheritableThreadLocal 可以方便地在父子线程之间传递数据,但是需要注意线程安全问题。如果多个线程同时访问同一个 InheritableThreadLocal 变量,需要保证线程安全。

三、源码分析


public class InheritableThreadLocal<T> extends ThreadLocal<T> {
   // 是一个回调方法,在子线程中初始化该线程本地变量的值。该方法的参数是父线程中该变量的值,返回值是父线程中该变量的值。
    protected T childValue(T parentValue) {
        return parentValue;
    }

    // 返回当前线程的 inheritableThreadLocals 属性,该属性是一个 ThreadLocalMap 对象,用于存储 InheritableThreadLocal 类的线程本地变量
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
  // 创建一个新的 ThreadLocalMap 对象,并将其赋值给当前线程的 inheritableThreadLocals 属性
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

InheritableThreadLocal类继承自 ThreadLocal 类,拥有 ThreadLocal 的特性,每个线程都有一个独立的变量副本。不同之处在于,InheritableThreadLocal 变量可以被子线程继承。这个类包含了三个方法:

  1. childValue(T parentValue) 方法:该方法是一个回调方法,用于在子线程中创建该变量的值。默认情况下,子线程会继承父线程的 InheritableThreadLocal 变量副本,但是如果需要在子线程中创建一个新值,可以通过重写这个方法来实现。这个默认实现是简单地返回父线程的值,意味着子线程会与父线程共享同一个值。如果需要在子线程中创建一个新值,可以通过重写这个方法来提供自己的逻辑。

  1. getMap(Thread t) 方法:该方法返回指定线程的 InheritableThreadLocalMap 对象,这个对象包含了该线程的所有 InheritableThreadLocal 变量。如果该线程的InheritableThreadLocal属性为null,则会返回null。

  1. createMap(Thread t, T firstValue) 方法:这个方法用于在指定线程中创建 InheritableThreadLocalMap 对象,并将第一个变量值放入其中。如果该线程已经有 InheritableThreadLocalMap 对象,则不会创建新的对象。

四、InheritableThreadLocal 设置值和获取值流程


4.1 set 流程

  1. 首先创建一个 InheritableThreadLocal 实例,例如:InheritableThreadLocal<String> local = new InheritableThreadLocal<>();

  1. 调用 local .set(value) 方法设置值(实际上调用的是InheritableThreadLocal父类中的set方案进行设置值)。

  1. 获取当前线程;

  1. 根据当前线程从InheritableThreadLocal 中获取对应的ThreadLocalMap对象。

  1. 如果ThreadLocalMap对象存在,则使用set方法将ThreadLocal对象和值保存到ThreadLocalMap对象中。

  1. 如果ThreadLocalMap对象不存在,说明当前线程还没有ThreadLocalMap对象,此时调用InheritableThreadLocal的createMap方法为其创建一个ThreadLocalMap对象,将ThreadLocal对象和值保存到其中,并将ThreadLocal赋值给当前线程inheritableThreadLocals属性。

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

4.2 get 流程


  1. 获取当前线程;

  1. 根据当前线程从InheritableThreadLocal中获取对应的ThreadLocalMap对象。

  1. 如果ThreadLocalMap对象存在,则从中获取ThreadLocal对象对应的Entry对象,

  1. 如果Entry对象存在,则返回其值,否则返回null。

  1. 如果ThreadLocalMap对象不存在,说明当前线程还没有ThreadLocalMap对象,此时需要使用setInitialValue方法来为其设置一个初始值,并返回该值。

// 如果没有获取到数据,则会初始一个数据,将线程当作key,null 当作value 放入ThreadLocalMap中
public T get() {
  // 获取当前线程。
    Thread t = Thread.currentThread();
    // 根据当前线程从InheritableThreadLocal中获取ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    // 如果ThreadLocalMap对象存在
    if (map != null) {
        // 从中获取ThreadLocal对象对应的Entry对象。
        ThreadLocalMap.Entry e = map.getEntry(this);
        // 如果Entry对象存在,则返回其值
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 如果ThreadLocalMap对象不存在,说明当前线程还没有ThreadLocalMap对象,此时需要使用setInitialValue方法来为其设置一个初始值,并返回该值。
    return setInitialValue();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值