InheritableThreadLocal

简介: ThreadLocal子线程无法继承父线程变量,而InheritableThreadLocal可实现父子线程间数据传递。其原理是在Thread初始化时,复制父线程的inheritableThreadLocals到子线程,通过createInheritedMap创建新的ThreadLocalMap,实现值的继承,适用于需传递上下文的场景。

ThreadLocal固然很好,但是子线程并不能取到父线程的ThreadLocal的变量,比如下面的代码:

private static ThreadLocal integerThreadLocal = new ThreadLocal<>();
private static InheritableThreadLocal inheritableThreadLocal =
new InheritableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
integerThreadLocal.set(1001); // father
inheritableThreadLocal.set(1002); // father
new Thread(() -> System.out.println(Thread.currentThread().getName() + ":"

                                    + integerThreadLocal.get() + "/"
                                    + inheritableThreadLocal.get())).start();

}
//output:
Thread-0:null/1002

使用ThreadLocal不能继承父线程的ThreadLocal的内容,而使用InheritableThreadLocal时可以做到的,这就可以很好的在父子线程之间传递数据了。下面我们分析一下InheritableThreadLocal的实现细节,下面展示了InheritableThreadLocal提供的方法:

InheritableThreadLocal方法

InheritableThreadLocal继承了ThreadLocal,然后重写了上面三个方法,所以除了上面三个方法之外,其他所有对InheritableThreadLocal的调用都是对ThreadLocal的调用,没有什么特别的。我们上文中提到了Thread类,里面有我们本文关心的两个成员,我们来看一下再Thread中做了哪些工作,我们跟踪一下new一个Thread的调用路径:

new Thread()
init(ThreadGroup g, Runnable target, String name, long stackSize)

init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals)
->
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
createInheritedMap(ThreadLocalMap parentMap)
ThreadLocalMap(ThreadLocalMap parentMap)

上面列出了最为关键的代码,可以看到,最后会调用ThreadLocal的createInheritedMap方法,而该方法会新建一个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 key = (ThreadLocal) 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] = c;
size++;
}
}
}
}

parentMap就是父线程的ThreadLocalMap,这个构造函数的意思大概就是将父线程的ThreadLocalMap复制到自己的ThreadLocalMap里面来,这样我们就可以使用InheritableThreadLocal访问到父线程中的变量了。
对ThreadLocal更为具体和深入的分析将在其他的篇章中进行,本文点到即可,为了深入理解ThreadLocal,可以阅读ThreadLocalMap的源码,以及可以在项目中多思考是否可以使用ThreadLocal来做一些事情,比如,如果我们具有这样一种线程模型,一个任务从始至终只会被一个线程执行,那么可以使用ThreadLocal来计算运行该任务的时间。

相关文章
|
17小时前
3.5 文档的分页查询
统计查询使用count()方法,可统计集合中符合条件的记录数量。语法为db.collection.count(query, options)。如统计comment集合全部记录:db.comment.count();按条件统计userid为1003的记录数:db.comment.count({userid:&quot;1003&quot;})。默认返回所有匹配文档的数量。
|
17小时前
|
XML NoSQL Java
5.3 技术选型
本节介绍MongoDB的Java连接驱动mongodb-driver及SpringDataMongoDB持久层框架,通过搭建文章微服务工程,配置Spring Boot整合MongoDB,实现项目初始化与启动。
|
17小时前
|
存储 NoSQL MongoDB
3.2 数据库操作
MongoDB中使用`use 数据库名`选择或创建数据库,若不存在则自动创建。通过`show dbs`查看所有数据库,`db`查看当前库。集合需插入文档后才真正创建。数据库名须为非空、小写、不超过64字节的UTF-8字符串,不可含特殊字符。保留库包括admin(权限管理)、local(本地数据)和config(分片信息)。
|
17小时前
|
存储 NoSQL Linux
2.4 Linux系统中的安装启动和连接
本文介绍在Linux系统部署单机MongoDB用于生产环境的完整步骤,包括下载、解压、目录配置、日志与数据路径设置、配置文件编写及服务启停方法。操作类似Windows,通过配置`mongod.conf`实现后台运行,支持命令行与图形工具连接,并提供防火墙处理与安全关闭服务方案,确保稳定运行。
|
17小时前
|
NoSQL MongoDB
2.3 Compass-图形化界面客户端
前往MongoDB官网下载MongoDB Compass,安装版按提示安装,压缩版解压后运行MongoDBCompassCommunity.exe。打开后输入主机地址、端口等信息,点击连接即可使用。
|
17小时前
|
存储 NoSQL 关系型数据库
4-MongoDB索引知识
MongoDB索引通过B树结构提升查询效率,避免全表扫描。支持单字段和复合索引,前者适用于单一字段排序与查询,后者按字段顺序构建,优化多条件查询与排序操作,显著提升大数据量下的查询性能。
|
17小时前
5.5 文章评论实体类的编写
创建实体类Comment,位于cn.itcast.article.po包中,包含评论的ID、内容、发布时间、用户信息、点赞数、回复数、状态及关联文章ID等属性,并提供getter/setter及toString方法,用于封装评论数据。
|
17小时前
3.5.3 排序查询
sort()方法用于对查询结果排序,1为升序,-1为降序,可按多字段排序。语法:db.集合名.find().sort({字段:1/-1})。与skip()、limit()联用时,执行顺序为先排序,再跳过,最后限制显示。
|
17小时前
3.5.2 分页列表查询
使用limit()限制查询返回的记录数,skip()跳过指定数量数据,实现分页。如每页2条:第一页skip(0).limit(2),第二页skip(2).limit(2),以此类推,默认limit为20,skip为0。