我们在使用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<String> threadLocal = new ThreadLocal<>();
//可以获取父线程的数据
// public static InheritableThreadLocal<String> 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. * <p> * 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成员变量上。
这里我们可以看到一个inheritableThreadLocals成员变量。该成员变量是InheritableThreadLocal类用来存储父线程数据用的。稍后我们会提及
这里可以说明了,为什么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方法,故此可以拿到父线程的数据