👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
📚欢迎订阅专栏,专栏名《在2B工作中寻求并发是否搞错了什么》
本文涉及InheritableThreadLocal和TTL,从源码的角度,分别分析它们是怎么实现父子线程传递的。
建议先了解ThreadLocal。
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
【Java并发】【ThreadLocal】适合初学体质的ThreadLocal
ThreadLocal存在的问题
众所周知,ThreadLocal并没有解决父子间线程传递的问题,比如下面的代码。
public static void main(String[] args) throws InterruptedException {
ThreadLocal<String> threadLocal = new ThreadLocal<>();
// threadLocal set值
threadLocal.set("main thread info");
System.out.println("main thread get: " + threadLocal.get());
// 启动子线程
new Thread(() -> System.out.println("sub thread get: " + threadLocal.get())).start();
threadLocal.remove();
}
输出结果
main thread get: main thread info
sub thread get: null
InheritableThreadLocal实现父子线程传递
将ThreadLocal换为InheritableThreadLocal:
public static void main(String[] args) throws InterruptedException {
InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
// threadLocal set值
threadLocal.set("main thread info");
System.out.println("main thread get: " + threadLocal.get());
// 启动子线程
new Thread(() -> System.out.println("sub thread get: " + threadLocal.get())).start();
threadLocal.remove();
}
输出结果
main thread get: main thread info
sub thread get: main thread info
🤔,那我们什么我换成InheritableThreadLocal就可以了呢?
省流版:原理就是,主线程创建子线程的时候,子线程会拷贝1份主线程的ThreadLocalMap。

当我们InheritableThreadLocal在set值的时候:
初始化当前线程的ThreadLocalMap,InheritableThreadLocal会,new一个ThreadLocalMap,赋值给当前线程的inheritableThreadLocals字段。(而ThreadLocal的逻辑是,new一个ThreadLocalMap,赋值给当前线程的threadLocals字段)
// ThreadLocal#set
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
// 👇初始化ThreadLocalMap,createMap调用子类InheritableThreadLocal类的实现
createMap(t, value);
}
}
// InheritableThreadLocal#createMap
void createMap(Thread t, T firstValue) {
// 当前线程的inheritableThreadLocals字段
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
// ThreadLocal#createMap
void createMap(Thread t, T firstValue) {
// 当前线程的threadLocals字段
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
聪明的你一定会问了,主播,主播,赋值给inheritableThreadLocals有什么用呢?
那这可是大有说法的,让我们从Thread类开始说起,当我们在主线程,new Thread()创建子线程的时候,Thread类的init方法里有个if判断:
- 我们重点看,
parent.inheritableThreadLocals != null,因为inheritableThreadLocals我们在set的时候已经赋值了,所以这里为true。 - 而
inheritThreadLocals是init方法的入参,我们很少使用到,这样的方式创建线程Thread(Runnable target, AccessControlContext acc),所以大部分情况都是true。
如果这两个条件都为true的话,那么会将主线程的ThreadLocalMap数据拷贝到子线程的inheritableThreadLocals里。
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
...
Thread parent = currentThread();
...
// 重点在这里,将主线程的ThreadLocalMap拷贝到子线程的inheritableThreadLocals里。
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
createInheritedMap将主线程的ThreadLocalMap拷贝到子线程里。
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
// 将主线程的ThreadLocalMap数据拷贝到子线程里
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
// 这里需要重新哈希槽位
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h
从源码看InheritableThreadLocal和TTL父子线程传递


最低0.47元/天 解锁文章
395

被折叠的 条评论
为什么被折叠?



