深入解析inheritablethreadlocal实现原理 背景 原因 解决方案 案例:

说 InheritableThreadLocal 之前我们先说下ThreadLocal

可以去看看 : 对ThreadLocal的思考

背景

前几天 在项目中集成hystrix,结果从ThreadLocal中获取不到数据。

原因

hystrix 会隔离线程,提高系统的安全性

解决方案

把 ThreadLocal 换成 InheritableThreadLocal

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public class extends Thread{

static ThreadLocal<String> threadLocal = new ThreadLocal<>();

public static void main(String[] args){
threadLocal.set("123");
new ThreadLocalTest().start();
}


public void run() {
System.out.println(threadLocal.get()+"---");
}
}

运行结果: 子线程中 获取不到 变量

1
2
3
null---

Process finished with exit code 0

//解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class  extends Thread{

static InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();

public static void main(String[] args){
threadLocal.set("123");
new ThreadLocalTest().start();
}


public void run() {
System.out.println(threadLocal.get()+"---");
}
}

1
2
3
123---

Process finished with exit code 0

使用 InheritableThreadLocal 解决了线程隔离获取不到变量的问题,
当然我们不能 知其然而不知道其所以然。
那么为什么InheritableThreadLocal 可以在线程隔离的情况下获取到值呢?
让我们走进源代码:
这是 Thread 的源代码的部分源码大概在418行,这段代码会在 Thread 初始化的时候执行,
Thread 维护了 inheritableThreadLocals,threadLocals 两个变量 类型都是 ThreadLocalMap
,在下面这段代码中看到 它判断了inheritableThreadLocals 是否为空,不为空就传入 createInheritedMap 往下看 createInheritedMap的源码

1
2
3
4
5
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

this.stackSize = stackSize;

此处生成了一个新增 ThreadLocalMap 返回 然后 赋值给了 Thread的this.inheritableThreadLocals,
流程就是
Thread初始化->创建一个新的ThreadLocalMap(存储了当前线程变量的)返回—->这步 看 InheritableThreadLocal的源码

1
2
3
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}

可以看到 InheritableThreadLocal 重写了getMap,createMap方法,这两方法传入的参数都是Thread, return t.inheritableThreadLocals; 这里其实就是引用到了 上一步 返回到 Thread的inheritableThreadLocals变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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为什么能实现Thread的隔离还能获取变量。

如果本文对您有帮助,请不要吝啬您的点赞。谢谢!