【并发编程】ThreadLocal的兄弟InheritableThreadLocal
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。
引子
public class InheritableThreadLocalDemo {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("mainThread");
System.out.println("value:"+threadLocal.get());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
String value = threadLocal.get();
System.out.println("value:"+value);
}
});
thread.start();
}
}
上面代码中在主线程中设置了一个ThreadLocal变量,并将其值设置为mainThread。然后有在主线程中开启了一个子线程thread,并试图获取在主线程中set的ThreadLocal变量的值。但是结果如下:
value:mainThread
value:null
通过前面的文章介绍,对于上面的结果我们也就非常容易理解了。每个线程都会有一个自己的ThreadLocalMap,所以子线程在调用get方法拿值的时候其实访问的是自己的ThreadLocalMap,这个Map和主线程的Map是两个不同的对象,所以肯定是拿不到值的。
那么Java中有没有类似的对象能实现上面的功能呢?有,InheritableThreadLocal就能实现这样的功能,这个类能让子线程继承父线程中已经设置的ThreadLocal值。
InheritableThreadLocal简单使用
还是以上面的列子为列,我们只需要将ThreadLocal变成InheritableThreadLocal就行了。
public class InheritableThreadLocalDemo {
private static InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("mainThread");
System.out.println("value:"+threadLocal.get());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
String value = threadLocal.get();
System.out.println("value:"+value);
}
});
thread.start();
}
}
执行结果如下:
value:mainThread
value:mainThread
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,并且重写了getMap和createMap方法,区别就是将 ThreadLocal 中的 threadLocals 换成了 inheritableThreadLocals,这两个变量都是ThreadLocalMap类型,并且都是Thread类的属性。
下面就一步步来看下InheritableThreadLocal为什么能拿到父线程中的ThreadLocal值。
step1:InheritableThreadLocal获取值先调用了get方法,所以我们直接看看get方法都做了些啥。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
从上面的代码可以看出,get方法和ThreadLocal中是一样的,唯一有区别的就是其中的getMap方法重写了,返回的是inheritableThreadLocals属性。这个属性也是一个ThreadLocalMap类型的变量。那么从这边就可以推断出来:肯定是在某处将父线程中的ThreadLocal值赋值到了子线程的inheritableThreadLocals中。
step2:在源代码中搜索哪些地方使用到了inheritableThreadLocals这个属性,最后找到这段代码:
private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name.toCharArray();
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
if (security != null) {
g = security.getThreadGroup();
}
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess();
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
//1. 这边先判断了父线程中inheritableThreadLocals属性是否为空,不为空的话就复制给子线程
if (parent.inheritableThreadLocals != null)
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
上面的代码印证了我们的猜想。需要注意的是一旦子线程被创建以后,再操作父线程中的ThreadLocal变量,那么子线程是不能感知的。因为父线程和子线程还是拥有各自的ThreadLocalMap,只是在创建子线程的“一刹那”将父线程的ThreadLocalMap复制给子线程,后续两者就没啥关系了。
【并发编程】ThreadLocal的兄弟InheritableThreadLocal的更多相关文章
- 9.并发编程--ThreadLocal
并发编程--ThreadLocal 1. ThreadLocal : * 线程局部变量,是一种多个线程间并发访问变量的解决方案. * 与其使用synchronized等加锁的方式,ThreadLoca ...
- 并发编程之详解InheritableThreadLocal类原理
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 在Java并发编 ...
- java并发编程(九)ThreadLocal & InheritableThreadLocal
参考文档: https://blog.csdn.net/u012834750/article/details/71646700 threadlocal内存泄漏:http://www.importnew ...
- 并发编程 01—— ThreadLocal
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- Java并发编程:ThreadLocal
Java并发编程:深入剖析ThreadLocal Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用 ...
- Java并发编程--理解ThreadLocal
另一篇博文:Hibernet中的ThreadLocal使用 http://www.cnblogs.com/gnivor/p/4440776.html 本文参考:http://blog.csdn.net ...
- Java并发编程:深入剖析ThreadLocal(转载)
Java并发编程:深入剖析ThreadLocal(转载) 原文链接:Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadL ...
- 并发编程(四):ThreadLocal从源码分析总结到内存泄漏
一.目录 1.ThreadLocal是什么?有什么用? 2.ThreadLocal源码简要总结? 3.ThreadLocal为什么会导致内存泄漏? 二.ThreadLoc ...
- (转)Java并发编程:深入剖析ThreadLocal
Java并发编程:深入剖析ThreadLoca Java并发编程:深入剖析ThreadLocal 说下自己的理解:使用ThreadLocal能够实现空间换时间,重在理解ThreadLocal是如何复制 ...
随机推荐
- 使用Typescript重构axios(十八)——请求取消功能:总体思路
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 【Elasticsearch 7 探索之路】(二)文档的 CRUD 和批量操作
上一篇,我们介绍了什么是 Elasticsearch,它能做什么用以及基本概念(索引 Index.文档 Document.类型 Type)理解.这篇主要对 文档的基本 CRUD 和 倒排索引进行讲解. ...
- php+mysql 实现无限极分类
php+mysql 实现无限极分类<pre>id name pid path 1 电脑 0 0 2 手机 0 0 3 笔记本 1 0-1 4 超级本 3 0-1-3 5 游戏本 3 0-1 ...
- 实现 sqrt(x):二分查找法和牛顿法
最近忙里偷闲,每天刷一道 LeetCode 的简单题保持手感,发现简单题虽然很容易 AC,但若去了解其所有的解法,也可学习到不少新的知识点,扩展知识的广度. 创作本文的思路来源于:LeetCode P ...
- 关于Jvm的见解(二)
栈管运行,堆管存储!!! 栈呢,也叫作栈内存,主要管java程序的运行,在线程创建时创建,生命周期和线程一致,只要线程一结束,该栈就被GC,是线程私有的.基本类型的变量和对象的引用数据类型的变量都在栈 ...
- Dubbo的应用
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- 设计模式(Java语言)-单例模式
单例模式,简而言之就是在整个应用程序里面有且仅有一个实例,在程序的任何时候,任何地方获取到的该对象都是同一个对象.单例模式解决了一个全局的类被频繁创建和销毁的,或者每次创建或销毁都需要消耗大量cpu资 ...
- 启动Spring Tool Suite 4时出现 could not find tools.jar spring boot live hovers....弹窗
第一步:检查一下STS启动时的加载环境 Help —› About Spring Tool Suite 4 —› Installation Details —› Configuration 本人已经 ...
- [TCP/IP] 学习TCP/IP协议的笔记
1.我看的视频是https://www.bilibili.com/video/av10610680?from=search&seid=1733008388243131444这位大大的视频讲解. ...
- 领扣(LeetCode)最长公共前缀 个人题解
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...