详解InheritableThreadLocal类的使用与原理
在Java并发编程中,InheritableThreadLocal 与 ThreadLocal 都可以用于线程间通信,不同的是 InheritableThreadLocal 继承了 ThreadLocal,并且扩展了 ThreadLocal。使用类 InheritableThreadLocal 可使子线程继承父线程的值。相反,类 ThreadLocal 不能实现值继承。
使用示例:
public class LocalThread extends Thread {
private static InheritableThreadLocal local = new InheritableThreadLocal();
@Override
public void run() {
System.out.println("thread线程:"+ local.get());
}
public static void main(String[] args) throws InterruptedException {
local.set("main的值");
LocalThread t = new LocalThread();
t.start();
System.out.println("main线程:"+ local.get());
}
}
如果想要自定义 get() 方法默认值,具体操作也和 ThreadLocal 是一样的。
public class Local extends InheritableThreadLocal {
@Override
protected Object initialValue() {
return new Date();
}
}
InheritableThreadLocal 提供继承的同时还可以进行进一步的处理。代码如下:
public class Local extends InheritableThreadLocal {
@Override
protected Object initialValue() {
return new Date();
}
@Override
protected Object childValue(Object parentValue) {
return parentValue+"[子线程增强版]";
}
}
分析下 InheritableThreadLocal 类源码:
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
/**
* Computes the child's initial value for this inheritable thread-local
* variable as a function of the parent's value at the time the child
* thread is created. This method is called from within the parent
* thread before the child is started.
* <p>
* This method merely returns its input argument, and should be overridden
* if a different behavior is desired.
*
* @param parentValue the parent thread's value
* @return the child thread's initial value
*/
protected T childValue(T parentValue) {
return parentValue;
}
/**
* Get the map associated with a ThreadLocal.
*
* @param t the current thread
*/
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
/**
* Create the map associated with a ThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the table.
*/
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
可以看到,getMap() 方法和 creatMap() 方法都是重写的 ThreadLocal 类方法,区别在于把 ThreadLocal 中的 threadLocals 换成了 inheritableThreadLocals,这两个变量都是ThreadLocalMap类型,并且都是Thread类的属性,源码如下:
/* 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;
inheritableThreadLocal 如何实现值继承的呢?继续看下面的代码:
/**
* Construct a new map including all Inheritable ThreadLocals
* from given parent map. Called only by createInheritedMap.
*
* @param parentMap the map associated with parent thread.
*/
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] = c;
size++;
}
}
}
}
在构造方法的完整源代码算法中可以发现,子线程将父线程中的 table 对象以复制的方式赋值给子线程的 table 数组,这个过程是在创建 Thread 类对象时发生的,也就说明当子线程对象创建完毕后,子线程中的数据就是主线程中旧的数据,主线程使用新的数据时,子线程还是使用旧的数据,因为主子线程使用两个 Entry[] 对象数组各自存储自己的值。
这部分涉及到 Java 的值传递。对于对象来说,值的内容其实是对象的引用。当在父线程中修改对象的某一属性,子线程由于引用着相同对象,所以可以感知到,本质上是在操作同一块内存地址。
对于基本数据类型(int、long)来说,由于传递的是值,在父线程改变了数据后,子线程依旧使用的是旧的数据。这里尤其要提 String 字符串,String 虽然不是基本数据类型,但是由于内部字符数组被 final 修饰带来的不可变型,当父线程修改其 String 类型数据时,等于替换掉该 String 对象,而并不是修改原 String 对象的值,所以子线程依旧不会发生变化。
另外,重写类 InheritableThreadLocal 的 childValue() 方法可以对继承的值进行加工,比如通过调用clone() 方法返回 parentValue 的浅拷贝,以达到子线程无法影响父线程的目的。
详解InheritableThreadLocal类的使用与原理的更多相关文章
- 并发编程之详解InheritableThreadLocal类原理
[本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 在Java并发编 ...
- Python进阶——详解元类,metaclass的原理和用法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题第18篇文章,我们来继续聊聊Python当中的元类. 在上上篇文章当中我们介绍了type元类的用法,在上一篇文章当中我 ...
- RocketMQ详解(四)核心设计原理
专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...
- unity3D游戏开发之详解Animation类和Animator类
详解Animator类和Animation类 链接: http://wenku.baidu.com/link?url=SiaUYcdrNYjOYrWVDJSKGAYdJOntMTOhsVJtyBk2i ...
- 【python进阶】详解元类及其应用1
前言 元类在python中是很重要的一部分,我将分两次去讲解元类及其应用,此篇为详解元类及其应用第一篇,下面开始今天的说明~~~ 1. 类也是对象 在⼤多数编程语⾔中,类就是⼀组⽤来描述如何⽣成⼀个对 ...
- 【python进阶】详解元类及其应用2
前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...
- Unity3D - 详解Quaternion类(二)
OK,不做引子了,接上篇Unity3D - 详解Quaternion类(一)走起! 四.Quaternion类静态方法 Quaternion中的静态方法有9个即:Angle方法.Dot方法.Euler ...
- Unity3D - 详解Quaternion类(一)
一.简介 Quaternion又称四元数,由x,y,z和w这四个分量组成,是由爱尔兰数学家威廉·卢云·哈密顿在1843年发现的数学概念.四元数的乘法不符合交换律.从明确地角度而言,四元数是复数的不可交 ...
- Java网络编程和NIO详解6:Linux epoll实现原理详解
Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...
随机推荐
- 关于爬虫平台的架构实现和框架的选型(二)--scrapy的内部实现以及实时爬虫的实现
我们接着关于爬虫平台的架构实现和框架的选型(一)继续来讲爬虫框架的架构实现和狂阶的选型. 前面介绍了scrapy的基本操作,下面介绍下scrapy爬虫的内部实现架构如下图 1.Spiders(爬虫): ...
- MyBatis从入门到精通:第二章数据的创建与插入文件
数据库表的创建: create table sys_user ( id bigint not null auto_increment, ), user_password ), user_email ) ...
- 关于下载安装Photoshop CS6遇到的一些问题
关于安装Photoshop CS6顺带安装AdobeBridge CS6和Aobe Extension Manager CS6的问题 Bridge是PS的一款插件,它能兼容大多数AODBE公司的软件, ...
- s := time.Now().Format("20060102") go格式化
s := time.Now().Format("20060102") t := time.Unix(1362984425, 0) nt := t.Format("2006 ...
- error: 'commit' is not possible because you have unmerged files.
解决方案: 1.把修改的文件add下,如:git add bidder_mod/src/common/dragon_bidder_data.cc2.git commit
- 题解 AT2243 【正方形のチップ】
题意:在格子纸上: 给出格子的单位长度C,和在上面圆的半径R; 求出: 圆中有多少个完整的小正方形.(单位长度*单位长度) #include<cstdio> #include<cma ...
- classpath和classpath*区别
classpath和classpath*区别: classpath:只会到你的class路径中查找找文件. classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找. ...
- C语言入门2-程序设计的灵魂—算法及Raptor的应用
一. 什么是算法(5个特性) 算法就是 解决问题的方法和步骤. 算法为解决一个具体问题而采取的确定的 有限的 执行步骤 ,仅指 计算机 能执行的算法. 算法是程序设计的灵魂和核心 ...
- Flutter初体验--环境搭建
Fluter最近火了起来,它的有点很多,今天我做一篇在Windows下安装Flutter的教程. 一.下载 无论你要安装什么软件,都要先下载下来.我用的是SourceTree,地址: https ...
- APP爬虫(2)把小姐姐的图片down下来
APP爬虫(1)想学新语言,又没有动力,怎么办? 书接上文.使用appium在帖子列表界面模拟上划动作,捕捉不到列表的规律.上划结束后,列表只能获取到屏幕呈现的部分,而且下标还是从0开始的. 根据酸奶 ...