我们在使用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成员变量上。
![](https://img-blog.csdn.net/20170920001614464?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMzgwMzI2Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20170920001356287?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMzgwMzI2Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](https://img-blog.csdn.net/20170920001542492?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMzgwMzI2Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这里我们可以看到一个inheritableThreadLocals成员变量。该成员变量是InheritableThreadLocal类用来存储父线程数据用的。稍后我们会提及
![](https://img-blog.csdn.net/20170920001837528?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMzgwMzI2Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
这里可以说明了,为什么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方法,故此可以拿到父线程的数据