当前位置:网站首页>较真儿学源码系列-InheritableThreadLocal(逐行源码带你分析作者思路)
较真儿学源码系列-InheritableThreadLocal(逐行源码带你分析作者思路)
2022-07-01 18:46:00 【天瑕】
Java版本:8u261。
之前我写过对ThreadLocal源码进行分析的文章,感兴趣的话可以查看《较真儿学源码系列-ThreadLocal(逐行源码带你分析作者思路)》。
InheritableThreadLocal是ThreadLocal的子类,通过前面的分析可知,ThreadLocal只能在同一线程内进行变量的共享,而InheritableThreadLocal不仅可以在同一线程内进行变量的共享,而且可以在父子线程之间进行变量的共享。比如说在父线程a中创建了一个子线程b,那么在a线程中用InheritableThreadLocal包装的变量,在子线程b中也能获取的到。但需要注意的是:InheritableThreadLocal和ThreadLocal一样,在同级线程中依然不能共享变量的值。并且InheritableThreadLocal只能父传子,不能子传父(同时也不是任何时候都能父传子,只有在一开始初始化的时候才会进行数据传递,后面会看到这点)。
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的三个方法而已。而在getMap和createMap方法中可以看到inheritableThreadLocals这个属性,那么这个属性到底是干什么的呢?其实它跟threadLocals属性一样,都是放在Thread类中的属性:
public class Thread implements Runnable {
//...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* InheritableThreadLocal values pertaining to this thread. This map is
* maintained by the InheritableThreadLocal class.
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
//...
}正是因为有了inheritableThreadLocals这个属性,就可以让子线程来访问父线程中的本地变量。
在创建线程的时候,会调用到Thread类的init方法:
/**
* Thread:
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
//...
Thread parent = currentThread();
//...
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
/*
将父线程中inheritableThreadLocals的数据初始化到一个新的ThreadLocalMap中,
并赋值给子线程的inheritableThreadLocals
*/
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
//...
}这里省略了其他不相干逻辑,只需要来看一下inheritableThreadLocals的初始化过程,进一步跟踪第17行代码处:
/**
* ThreadLocal:
*/
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
//parentMap是父线程中的数据
return new ThreadLocalMap(parentMap);
}
/**
* 将父线程中的inheritableThreadLocals复制到一个新的ThreadLocalMap中
* 个人认为这里直接将parentMap返回回去应该也是可以的,但这里重新构建一个
* ThreadLocalMap感觉是为了做一遍清理工作,将Entry为null的哈希槽清理掉
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
//设置子线程的threshold
setThreshold(len);
//初始化子线程的table(因为是在子线程创建的时候调用到这里的,所以不需要判断是否已经初始化,这里一定是未初始化的)
table = new Entry[len];
//遍历父线程中的table
for (int j = 0; j < len; j++) {
//获取其中的Entry
Entry e = parentTable[j];
if (e != null) {
//获取当前槽中的Entry中保存的ThreadLocal
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
//这里会调用InheritableThreadLocal覆写的childValue方法,也就是返回e.value本身
Object value = key.childValue(e.value);
//构建一个新的Entry
Entry c = new Entry(key, value);
//获取哈希槽的位置
int h = key.threadLocalHashCode & (len - 1);
//通过线性探测的方式来找到要插入的位置
while (table[h] != null)
h = nextIndex(h, len);
//插入数据
table[h] = c;
//计数+1
size++;
}
}
}
}
/**
* InheritableThreadLocal:
* 第32行代码处:
*/
protected T childValue(T parentValue) {
return parentValue;
}完整的流程如下:
- 首先父线程调用set或get方法时,会调用InheritableThreadLocal覆写的getMap方法返回inheritableThreadLocals,但因为其没有初始化,所以会调用覆写的createMap方法来创建ThreadLocalMap,并赋值给inheritableThreadLocals。这样父线程的inheritableThreadLocals属性就不为null了;
- 接着父线程会调用set方法往父线程的inheritableThreadLocals属性中的table数组中进行赋值;
- 然后创建子线程的时候,会调用Thread类的init方法中的ThreadLocal.createInheritedMap方法。将父线程inheritableThreadLocals属性中的数据初始化到一个新的ThreadLocalMap中,并同时赋值给子线程的inheritableThreadLocals。这样子线程的inheritableThreadLocals属性中就有了父线程中的数据;
- 最后子线程在调用get方法的时候就能拿到父线程中的数据了。但是需要注意的是:子线程执行完毕后,父线程此时调用get方法拿到的还是之前父线程中的inheritableThreadLocals,并不是子线程会往其中更改过的ThreadLocalMap。也就是说子线程的数据不会传递给父线程,子线程只有在一开始初始化的时候才会同步父线程中的数据。
原创不易,未得准许,请勿转载,翻版必究
边栏推荐
- 事务隔离级别 gap锁 死锁
- Dom4j parsing XML, XPath retrieving XML
- 解决VSCode下载慢或下载失败的问题
- Actual combat of flutter - fast implementation of audio and video call application
- IPv4 address, subnet mask, gateway
- 集合对象值改变NULL值对象
- 奔赴山海之前,毕业季一定要做的那些事情
- Basic knowledge of audio coding and decoding
- IPv4地址、子网掩码、网关
- 音视频、编解码相关电子书、小工具,打包奉送!
猜你喜欢

精耕渠道共谋发展 福昕携手伟仕佳杰开展新产品培训大会

自定义插入页面标签以及实现类似通讯录的首字母搜索

How to correctly use vertx to operate redis (3.9.4 with source code analysis)

音视频、编解码相关电子书、小工具,打包奉送!

数字化转型企业成功的关键,用数据创造价值

AAAI2020: Real-time Scene Text Detection with Differentiable Binarization

Regular expression =regex=regular expression
![Thesis reading [distinctive late semantic graph for video capturing]](/img/d4/4f84a73a9127fa87bb0a74c4655d15.png)
Thesis reading [distinctive late semantic graph for video capturing]

【AI服务器搭建】CUDA环境

Salesmartly has some tricks for Facebook chat!
随机推荐
Optimization of video streaming with repeated requests in the case of unstable easygbs network
Les canaux de culture intensive s'efforcent de développer Fu Xin et Wei Shi jiajie pour organiser une conférence de formation sur les nouveaux produits
Brpc understanding
Ffmpeg avframe to cv:: mat
Wireshark packet analysis TCP, FTP
GB28181的NAT穿透
Uni app product classification
新窗口打开页面-window.open
安装sharp报错
CMU AI PhD 第一年总结
Detailed explanation of JUnit unit test framework
Why must we move from Devops to bizdevops?
Learning records of building thingsboard, an Internet of things platform
Opencv video quality detection -- sharpness detection
OpenCV视频质量诊断----视频遮挡诊断
A brief understanding of white box encryption technology
自定义插入页面标签以及实现类似通讯录的首字母搜索
uni-app商品分类
ffmpeg常用命令(二)
win10下使用msys+vs2019编译ffmpeg源码