InheritableThreadLocal类详解

我们在使用ThreadLocal类的时候,可以保证各个线程使用自己的数据,而不相互干扰。

但是如果我们有这样的一个需求,就是各个线程相互不干扰的情况下。各个线程的子线程可以访问到当前线程中的值。对于这个子线程来说就是访问父线程。

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
我们可以从源码中看出InheritableThreadLocal类继承了ThreadLocal这个类。

也就是说,该类具备了ThreadLocal类的能力。

此时我们可以运行一个demo

public class InheritableThreadLocalTest {

    public static void main(String[] args) throws InterruptedException {
        InheritableThreadLocalContext inheritableThreadLocalContext = new InheritableThreadLocalContext();
        inheritableThreadLocalContext.setValue("123");
        System.out.println(inheritableThreadLocalContext.getValue());

    }
}

public class InheritableThreadLocalContext {

    public static ThreadLocal threadLocal = new ThreadLocal<>();
    //可以获取父线程的数据
//    public static InheritableThreadLocal threadLocal = new InheritableThreadLocal<>();
    public void setValue(String s) {
        threadLocal.set(s);
    }

    public String getValue() throws InterruptedException {

        /*

        final String[] s = {null};
        Runnable runnable = () -> s[0] = threadLocal.get();
        Thread t = new Thread(runnable);
        t.start();
        Thread.sleep(1000);
        return s[0];
        */
        return threadLocal.get();
    }
}

我们可以发现,当我在子线程中去访问ThreadLocal对象的值的时候,获取值的时候,是获取不到的。但是我们将ThreadLocal类替换成InheritableThreadLocal类的时候,此时是可以获取到值的。也就是说,在各个不相关的线程不相互干扰的情况下,实现了子线程获取父线程数据的能力。

也就是该InheritableThreadLocal类最大的能力。

我们可以看一看该类的实现。

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    /**
     * Computes the child's initial value for this inheritable thread-local
     * variable as a function of the parent's value at the time the child
     * thread is created.  This method is called from within the parent
     * thread before the child is started.
     * 

* This method merely returns its input argument, and should be overridden * if a different behavior is desired. * * @param parentValue the parent thread's value * @return the child thread's initial value */ protected T childValue(T parentValue) { return parentValue; } /** * Get the map associated with a ThreadLocal. * * @param t the current thread */ ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } /** * Create the map associated with a ThreadLocal. * * @param t the current thread * @param firstValue value for the initial entry of the table. */ void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue); } }


这里有两个方法createMap和 getMap。复写了父类ThreadLocal类的方法。有分析过ThreadLocal源码的朋友可以知道。ThraedLocal 对象的值是保存在一个自己实现的Map中的。然后绑定到当前的Thread对象的 threadLocals成员变量上。

InheritableThreadLocal类详解_第1张图片

InheritableThreadLocal类详解_第2张图片InheritableThreadLocal类详解_第3张图片

InheritableThreadLocal类详解_第4张图片这里我们可以看到一个inheritableThreadLocals成员变量。该成员变量是InheritableThreadLocal类用来存储父线程数据用的。稍后我们会提及


InheritableThreadLocal类详解_第5张图片


这里可以说明了,为什么ThreadLocal类可以保证每个线程访问的数据相互都不干扰,因为数据是绑定在线程对象本身的。

我们再到Thread类的 init方法中去看下

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

//中间忽略一些代码

if (parent.inheritableThreadLocals != null)
    this.inheritableThreadLocals =
        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
上面代码的意思是如果父线程的InheritableThreadLocals成员变量不为空,将父线程的InheritableThreadLocals成员变量拷贝到当前线程的

InheritableThreadLocals变量上来。而且,在上面我们可以看到InheritableThreadLocal类复写了ThreadLocal类的getMap和createMap方法,故此可以拿到父线程的数据

你可能感兴趣的:(Java)