在了解InheritableThreadLocal先确定你已经了解了ThreadLocal
我们知道ThreadLocal可以实现线程之间值的传递,但是如果是父子线程呢?
我们来看一个简单的例子
private static final ThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
testInheritableThreadLocal();
}
public static void testInheritableThreadLocal() {
inheritableThreadLocal.set("set-inheritableThreadLocal");
threadLocal.set("set-threadLocal");
new Thread(() -> {
String threadLocalCtx = threadLocal.get();
String inheritableThreadLocalCtx = inheritableThreadLocal.get();
System.out.println("currentThread:" + Thread.currentThread() + ", get threadLocalCtx:" + threadLocalCtx);
System.out.println("currentThread:" + Thread.currentThread() + ", get inheritableThreadLocalCtx:" + inheritableThreadLocalCtx);
}).start();
}
复制代码
输出结果:
可以看到InheritableThreadLocal
是完成了父子线程值的传递,而ThreadLocal
则丢失了值
InheritableThreadLocal
是如何做到的呢?我们来一起简单了解下
类UML图
可以看到InheritableThreadLocal
是继承ThreadLocal
的
核心源码分析
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
复制代码
InheritableThreadLocal 继承了 ThreadLocal 重写了几个方法
public T get() {
Thread t = Thread.currentThread();
// 该方法被重写,实际调用的是InheritableThreadLocal 的get方法
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();
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
复制代码
可以看到和ThreadLocal
相比并没有什么特殊的地方
我们可以看看ThreadLocal
的get方法
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();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
复制代码
就是在获取ThreadLocalMap
获取的是一个inheritableThreadLocals
类型和ThreadLocal
一样都是ThreadLocalMap
那么实现父子线程值传递的核心代码在哪里呢?其实是在Thread 类的构造方法里面,我们一起来看看
核心原理
这里是 Thread的构造方法,调用的还是不同参数的构造方法重载,我们直接看具体的实现类
private Thread(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security manager doesn't have a strong opinion
on the matter, use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(
SecurityConstants.SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
// 核心代码
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
this.tid = nextThreadID();
}
复制代码
核心代码
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
复制代码
可以看到在创建子线程的时候将父线程的ThreadLocalMap
传递赋值到子线程的ThreadLocalMap
了
这里需要注意的是一旦子线程被创建以后,再操作父线程中的ThreadLocal变量,那么子线程是不能感知的。因为父线程和子线程还是拥有各自的ThreadLocalMap,只是在创建子线程的时候通过构造方法将父线程的ThreadLocalMap复制给子线程,后续两者就没啥关系了