ThreadLocal的进化——InheritableThreadLocal
之前有介绍过 ThreadLocal,JDK 后来针对此做了一个升级版本 InheritableThreadLocal,今天就来好好介绍下。
为什么要升级
首先我们来想想,为什么要升级?这就要说起 ThreadLocal 的功能了。
我们知道,ThreadLocal 设计初衷是为了在多线程环境下,针对每一个线程能有一个自己的副本,这样可以在一定程度上解决多线程并发修改的问题。但是,我们可以在此基础上做一个拓展,比如context,我们可以利用 ThreadLocal 针对每一个线程都有一个自己的上下文,一般都是写成ThreadLocal<Context>,这样在这个线程上做的所有修改都可以被大家利用到。
此时设想一下,假如我们新建一个子线程,那这个子线程可以获取到父线程的context吗?理论上希望可以达成这样的效果,实际上呢?让我们看看:
public class ThreadLocalContext {
private static ThreadLocal<Context> context = new ThreadLocal<>();
static class Context {
String name;
int value;
}
public static void main(String[] args) {
Context context = new Context();
context.name = "mainName";
context.value = 10;
ThreadLocalContext.context.set(context);
Thread childThread = new Thread(
new Runnable() {
@Override
public void run() {
Context childContext = ThreadLocalContext.context.get();
System.out.println(childContext.name);
System.out.println(childContext.value);
}
}
);
childThread.start();
}
}
运行 main 方法之后,直接在子线程中抛错,这样确实符合我们的预期,但如果我们想达到子线程可以获取到父线程的 context这样的效果该如何做呢?
首先想到的就是在生成子线程的时候,将父线程 ThreadLocal 里的值传给子线程。这样做虽然能达到效果,但过程比较繁杂,且代码侵入性强。
这个时候就可以用InheritableThreadLocal了。
什么是 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);
}
}
首先它继承自 ThreadLocal,那么它其实就是 ThreadLocal 的一个拓展版本,接下来就是这三个方法,其实这三个方法在 ThreadLocal 都是有的,我们来看看:
T childValue(T parentValue) {
throw new UnsupportedOperationException();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
除了childValue方法在 ThreadLocal 中是抛出异常的,其余两个方法在两个类中都几乎是一样,只是针对的对象不同而已,但threadLocals和inheritableThreadLocals都是ThreadLocal.ThreadLocalMap类型,这个在之前的文章中有说过,就是一个 key 为弱引用的 Entry,这个倒不是重点。
我们再来看看 inheritableThreadLocals 是在何时被初始化的,从源码可以得知:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
// 省略无关代码
...
Thread parent = currentThread();
...
// 省略无关代码
...
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}
当我们通过父线程调用 Thread 的构造方法生成一个子线程时,其构造方法最终会调用这个 init 方法。从这儿可以看出, inheritableThreadLocals 是来自于父线程的 inheritableThreadLocals,那这样也就解释了为什么 inheritableThreadLocals 支持在子线程中使用父线程中存储的变量。
如何使用
让我们还是回到上文提到的 context 的例子,用 InheritableThreadLocal 进行改造:
public class ThreadLocalContext {
private static InheritableThreadLocal<Context> context = new InheritableThreadLocal<>();
static class Context {
String name;
int value;
}
public static void main(String[] args) {
Context context = new Context();
context.name = "mainName";
context.value = 10;
ThreadLocalContext.context.set(context);
Thread childThread = new Thread(
new Runnable() {
@Override
public void run() {
Context childContext = ThreadLocalContext.context.get();
System.out.println(childContext.name);
System.out.println(childContext.value);
}
}
);
childThread.start();
}
}
运行后,不仅没有抛出异常,而且在子线程中输出了父线程设置好的值。皆大欢喜!
总结
今天分享了 InheritableThreadLocal,主要是因为周三在携程的分享会上听到了别人谈了这方面的分享,主讲人讲了一个更加普遍的问题,如果我们用线程池提交任务的话,线程池中的线程在执行任务时,如何能够获得提交任务的线程的 context,这时就要用到阿里的开源组件 TTL,我会在之后进行介绍。
加入携程也有1个月了,虽然感受到大公司有不少的弊端,比如沟通难等,但也有不少的优点,比如技术分享会,虽然也是忙里偷闲去参加的,但有了更多和技术相关的可以学习和交流的机会,也挺好的。
有兴趣的话可以访问我的博客或者关注我的公众号、头条号,说不定会有意外的惊喜。
公众号:健程之道


ThreadLocal的进化——InheritableThreadLocal的更多相关文章
- 【并发编程】ThreadLocal的兄弟InheritableThreadLocal
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 引子 public class InheritableT ...
- ThreadLocal的进化——TransmittableThreadLocal
上一篇文章中,我们谈到了 InheritableThreadLocal,它解决了 ThreadLocal 针对父子线程无法共享上下文的问题.但我们可能听说过阿里的开源产品TransmittableTh ...
- ThreadLocal系列(二)-InheritableThreadLocal的使用及原理解析
ThreadLocal系列之InheritableThreadLocal的使用及原理解析(源码基于java8) 上一篇:ThreadLocal系列(一)-ThreadLocal的使用及原理解析 下一篇 ...
- ThreadLocal (二):什么时候使用 InheritableThreadLocal
一.ThreadLocal 在父子线程传递的问题 public class InheritableThreadLocalDemo { // 全局变量 // static ThreadLocal< ...
- java高并发系列 - 第24天:ThreadLocal、InheritableThreadLocal(通俗易懂)
java高并发系列第24篇文章. 环境:jdk1.8. 本文内容 需要解决的问题 介绍ThreadLocal 介绍InheritableThreadLocal 需要解决的问题 我们还是以解决问题的方式 ...
- java并发编程(九)ThreadLocal & InheritableThreadLocal
参考文档: https://blog.csdn.net/u012834750/article/details/71646700 threadlocal内存泄漏:http://www.importnew ...
- ThreadLocal 源码剖析
ThreadLocal是Java语言提供的用于支持线程局部变量的类.所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量(每个线程一个拷贝).在各个Java web的各种框架 ...
- ThreadLocal类详解:原理、源码、用法
以下是本文目录: 1.从数据库连接探究 ThreadLocal 2.剖析 ThreadLocal 源码 3. ThreadLocal 应用场景 4. 通过面试题理解 ThreadLocal 1.从数据 ...
- 并发编程 01—— ThreadLocal
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
随机推荐
- Requests库使用总结
概述 Requests是python中一个很Pythonic的HTTP库,用于构建HTTP请求与解析响应 Requests开发哲学 Beautiful is better than ugly.(美丽优 ...
- FreeSql v0.11 几个实用功能说明
FreeSql 开源发布快一年了,立志成为 .Net 平台方便好用的 ORM,仓库地址:https://github.com/2881099/FreeSql 随着不断的迭代更新,越来越稳定,也越来越强 ...
- count的一些用法
count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL count(1)包括了所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL count(列名)只包 ...
- C++中对C的扩展学习新增语法——函数重载
函数重载 1.函数重载语法 1.同一个作用域(全局作用域.命名空间作用域.类作用域) 2.参数个数不同 3.参数类型不同 4.参数顺序不同 代码实现: 当函数名字一样的时候,通过参数类型.参数个数.参 ...
- Linux 下的这些高效指令,是你快速学习的神器
Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络协议.它支持32位 ...
- dbstructsync 多套mysql环境表、字段、索引的差异sql产出(原创)
最近写了一个工具(比较两套测试环境数据库表.表字段.索引的差异) 功能:可以比较两套环境中mysql指定库中表.表字段及索引的差异,返回具体需要同步的执行sql A环境的数据库db 作为sourced ...
- C# UTM坐标和WGS84坐标转换小工具
工具根据:http://home.hiwaay.net/~taylorc/toolbox/geography/geoutm.html js代码改编 工具源码github:https://github. ...
- js数组和集合互转
js数组和集合互转可用于去重: 数组转集合 var arr = [55, 44, 65]; var set = new Set(arr); console.log(set.size === arr ...
- Java描述设计模式(23):访问者模式
本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 电竞是游戏比赛达到"竞技"层面的体育项目.利用电子设备作为运动器械进行的.人与人之间的智力对抗 ...
- .NET Core 3.0 使用Nswag生成Api文档和客户端代码
摘要 在前后端分离.Restful API盛行的年代,完美的接口文档,成了交流的纽带.在项目中引入Swagger (也称为OpenAPI),是种不错的选择,它可以让接口数据可视化.下文将会演示 利用N ...