【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

在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());
} }

分析下 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 的浅拷贝,以达到子线程无法影响父线程的目的。

代码如下:

public class Local extends InheritableThreadLocal {

    @Override
protected Object initialValue() {
return new Date();
} @Override
protected Object childValue(Object parentValue) {
return parentValue+"[子线程增强版]"; // parentValue.clone();
}
}

版权声明

【本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

并发编程之详解InheritableThreadLocal类原理的更多相关文章

  1. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  2. 详解InheritableThreadLocal类的使用与原理

    在Java并发编程中,InheritableThreadLocal 与 ThreadLocal 都可以用于线程间通信,不同的是 InheritableThreadLocal 继承了 ThreadLoc ...

  3. java并发编程 | 线程详解

    个人网站:https://chenmingyu.top/concurrent-thread/ 进程与线程 进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配 ...

  4. 并发编程Semaphore详解

    Semaphore的作用:限制线程并发的数量 位于 java.util.concurrent 下, 构造方法 // 构造函数 代表同一时间,最多允许permits执行acquire() 和releas ...

  5. Java并发编程--Volatile详解

    摘要      Volatile是Java提供的一种弱同步机制,当一个变量被声明成volatile类型后编译器不会将该变量的操作与其他内存操作进行重排序.在某些场景下使用volatile代替锁可以减少 ...

  6. Java并发编程(详解wait(), notify(),sleep())

    http://blog.csdn.net/luckyzhoustar/article/details/48179161

  7. InheritableThreadLocal类原理简介使用 父子线程传递数据详解 多线程中篇(十八)

      上一篇文章中对ThreadLocal进行了详尽的介绍,另外还有一个类: InheritableThreadLocal 他是ThreadLocal的子类,那么这个类又有什么作用呢?   测试代码 p ...

  8. Java并发关键字Volatile 详解

    Java并发关键字Volatile 详解 问题引出: 1.Volatile是什么? 2.Volatile有哪些特性? 3.Volatile每个特性的底层实现原理是什么? 相关内容补充: 缓存一致性协议 ...

  9. 深入解析ThreadLocal 详解、实现原理、使用场景方法以及内存泄漏防范 多线程中篇(十七)

    简介 从名称看,ThreadLocal 也就是thread和local的组合,也就是一个thread有一个local的变量副本 ThreadLocal提供了线程的本地副本,也就是说每个线程将会拥有一个 ...

随机推荐

  1. [Objective-C] 008_Foundation框架之NSArray与NSMutableArray

    在Cocoa Foundation中NSArray和NSMutableArray 用于对象有序集合,NSArray和NSMutableArray类最大的区别是:NSArray是不可变,NSMutabl ...

  2. (八)Filter&ThreadLocal实现处理事务

    ConnectionContext.java package com.aff.bookstore.web; import java.sql.Connection; public class Conne ...

  3. Java实现洛谷 P1616 疯狂的采药

    题目背景 此题为NOIP2005普及组第三题的疯狂版. 题目描述 LiYuxiang是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他 ...

  4. Java实现 蓝桥杯VIP 算法训练 明明的随机数

    问题描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应 ...

  5. JavaScript实现html购物车代码

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Java 实现 蓝桥杯 历届试题 分糖果

    问题描述 有n个小朋友围坐成一圈.老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏: 每个小朋友都把自己的糖果分一半给左手边的孩子. 一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数 ...

  7. PAT 人口普查

    某城镇进行人口普查,得到了全体居民的生日.现请你写个程序,找出镇上最年长和最年轻的人. 这里确保每个输入的日期都是合法的,但不一定是合理的,假设已知镇上没有超过 200 岁的老人,而今天是 2014 ...

  8. java之单点登录(SSO)

    单点登录(SSO):SSO是指在多个应用系统中个,用户只需要登陆一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一用户的登陆的机制. SSO的实现过程: 通过上述 ...

  9. CSAPP 5 - 优化程序性能

    CSAPP 5 - 优化程序性能 1. 概述 首当其冲的,还是要编写出好的算法和数据结构,优化内部结构 其次才是编写出能让编译器 易优化的,高效的可执行代码.这点在特定的机器上可能有着特定的不同的优化 ...

  10. 微信小程序 简单获取屏幕视口高度

    由于小程序的宽度是固定的 750rpx,我们可以先用wx.getSystemInfo 来获取可使用窗口的宽高(并非rpx),结合750rpx的宽度算出比例,再用比例来算出高度 let that = t ...