子线程无法拿到父线程的变量怎么办?|Java 开发实战

简介: 数据在哪个线程存储,就要从哪个线程读取,子线程是读取不到的

开篇

数据在哪个线程存储,就要从哪个线程读取,子线程是读取不到的。那如果想要读取该怎么办呢?

示例

遇到开篇说的这种情况,可以使用InheritableThreadLocal来帮助我们解决这类问题,InheritableThreadLocalThreadLocal 的子类,我们用 InheritableThreadLocalThreadLocal来演示下效果,便于更直观的理解。

@Test
void contextLoads() throws InterruptedException {
    ThreadLocal threadLocal = new ThreadLocal();
    threadLocal.set("蒋老湿");
    System.out.println("threadLocal.get() = " + threadLocal.get());
    // 子线程是读取不到的
    new Thread(() -> {
        String name = Thread.currentThread().getName();
        System.out.println(String.format("this is sub thread name:%s, threadLocal.get(): %s", name, threadLocal.get()));
    }).start();
    Thread.sleep(1000);
    // ThreadLocal 修改为 InheritableThreadLocal
    ThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
    inheritableThreadLocal.set("蒋老湿inheritableThreadLocal");
    System.out.println("inheritableThreadLocal.get() = " + inheritableThreadLocal.get());
    // 在子线程中也能获取到父线程 ThreadLocal 中的数据。
    new Thread(() -> {
        String name = Thread.currentThread().getName();
        System.out.println(String.format("this is sub thread name:%s, inheritableThreadLocal.get(): %s", name, inheritableThreadLocal.get()));
    }).start();
}
复制代码
Tests passed:1of1test-1s 20 ms
1s 20ms threadLocal.get0)= 蒋老湿  
15:20 ms
1s 20 ms  this is sub thread name: Thread o. threadLocal. get O null  
inheritableThreadLocal.getO)=蒋老混inheritableThreadLocal
this is sub thread name: Thread-1, inheritableThreadLocal.get ()  蒋老混inheritableThreadLocal 

InheritableThreadLocal解读

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
/** Creates an inheritable thread local variable.*/ public InheritableThreadLocal(){}
/** Computes the child's initial value for this inheritable thread-local...*/ protected T childvalue(T parentValue){
return parentValue;
}
/** Get the map associated with a ThreadLocal. ...* ThreadLocalMap getMap(Thread t){
return t.inheritableThreadLocals}
/** Create the map associated with a ThreadLocal...*/ void createMap(Thread t,T firstValue)
t.inheritableThreadLocals=new ThreadLocalMap(firstKey: this,firstValue);

以上有三个方法,分别是:

  • getMap():方法的返回值变成了 inheritableThreadLocals对象
  • createMap(): 构建出 ThreadLocalMap 的对象复制给inheritableThreadLocals
  • childValue(): 这个方法仅仅返回它的输入参数,并且应该被覆盖

和 ThreadLocal 相比,主要是保存数据的对象从 threadLocals属性 变为 inheritableThreadLocals属性。

set过程

ThreadLocalinheritableThreadLocal = newInheritableThreadLocal();
inheritableThreadLocal.set("蒋老湿inheritableThreadLocal");  

set方法会进入如下内容ThreadLocal#set(T value)

public void set(T value){ value:"蒋老湿inheritableThreadLocal"
Thread t=Thread.currentThread(); t: "Thread[main,5,main]" ThreadLocalMap map = getMap(t); map: null if(map ≠null){
map.set(this, value); map:null} else {
createMap(t,value); t:"Thread[main,5,main]”value:"蒋老湿inheritableT
}

才是会调用java.lang.InheritableThreadLocal#createMap,也就是给Thread类的inheritableThreadLocals变量赋值。

protected T childValue(T parentValue){  
return parentvalue; 
}
/** Get the map associated with a ThreadLocal. ...*/  
ThreadLocalMap getMap(Thread t){  
return t.inheritableThreadLocals: 
/** Create the map associated with a ThreadLocal. ...*/ 
void createMap(Thread t. T firstValue){ 
t.inheritableThreadLocals = new ThreadLocalMap( firstKey: this, firstValue);  

什么时候调用createMap

在创建子线程的时候,通过红框部分可以了解到,如果父线程存在 inheritableThreadLocals 变量且不为null,就调用 ThreadLocal.createInheritedMap() 为该线程的 inheritableThreadLocals 变量赋值。

@ private Thread(ThreadGroup g, Runnable target, String name, 
long stacksize, AccessControlContext acc, 
  boolean inheritThreadLocals){ 
  if(name = null){..} 
  this.name =name;  
  Thread parent = currentThread();  
  SecurityManager security = System.getSecuritvManager(): 
if(g = null) {...}  
/* ... */ 
  g.checkAccess();  
  /* ... */ 
if (security ≠ null) {...}  
g.addUnstarted(); 
  this.group =g;  
this.daemon = parent.isDaemon():  
this.priority = parent.getPriority(); 
if(security = null l1 isCcLOverridden(parent.getClass())) 
this.contextClassLoader = parent.getContextClassLoader(); 
  else  
this.contextClassLoader = parent.contextClassLoader;  
this.inheritedAccessControlContext =  
acc ≠ null ? acc :AccessController.getContext():
this.target = target; 
setPriority(priority);  
if(inheritThreadLocals 8G parent.inheritableThreadLocals≠null)  
  this.inheritableThreadLocals =  
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals): 
*Stash the specified stack size in case the vm cares *  
this.stacksize = stacksize; 

ThreadLocal.createInheritedMap 方法所做的事情,其实就是将父线程的 inheritableThreadLocals 变量值赋值给子线程的 inheritableThreadLocals 变量。因此,在子线程中就可以访问到父线程 ThreadLocal 中的数据了。

这种复制不是实时同步,是在子线程创建的一瞬间才将父线程inheritableThreadLocals 变量的值赋值给子线程,一旦子线程创建成功后,用户再次去修改了父线程inheritableThreadLocals变量的值(即修改了父线程 ThreadLocal 中的数据),此时子线程是感知不到这个变化的。所以这里是值传递,不是引用传递。

好啦,经过上面的介绍大家应该搞清楚InheritableThreadLocal是怎么一会事了吧

相关文章
|
28天前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
59 4
|
6天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
27天前
|
监控 Java 测试技术
Java开发现在比较缺少什么工具?
【10月更文挑战第15天】Java开发现在比较缺少什么工具?
34 1
|
28天前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
52 2
|
14天前
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
8天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
21 4
|
10天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
32 4
|
20天前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
71 8
|
15天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
16天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
33 2