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


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

    测试代码

     

    public class T25 {
    
    public static void main(String[] args) {
    
    //主线程中赋值
    ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
    
    InheritableThreadLocal<String> stringInheritableThreadLocal = new InheritableThreadLocal<>();
    
    stringThreadLocal.set("ThreadLocal string");
    stringInheritableThreadLocal.set("InheritableThreadLocal string");
    
    //子线程中分别打印两个变量的信息
    new Thread(() -> {
    System.out.println(
    Thread.currentThread().getName() + " ThreadLocal value :" + stringThreadLocal.get());
    System.out.println(Thread.currentThread().getName() + " InheritableThreadLocal value :"
    + stringInheritableThreadLocal.get());
    }).start();
    
    }
    }
    在上面的测试代码中,主线程中创建了两个变量,类型分别为:ThreadLocal和InheritableThreadLocal
    然后在主线程中创建了一个新的线程
    在新的线程中,尝试获取他们的值
    从打印信息可以看得出来
    对于ThreadLocal获取的值为null,而对于InheritableThreadLocal则能够获取到值
    image_5c77364a_7c3
    结论:
    在子线程中,可以获取到父线程的InheritableThreadLocal类型变量的值,而不能获取到ThreadLocal类型变量的值
    对于ThreadLocal我们已经有了详尽的分析,在Thread中有一个map,以ThreadLocal类型的变量作为key
    在子线程中,get方法自然是获取子线程中的map,很显然,子线程中的map并没有设置任何值,所以初始值null被读取出来
    但是,InheritableThreadLocal为什么能够读取出来?

    原理分析

    在Thread类中,有一个ThreadLocal.ThreadLocalMap类型的变量:inheritableThreadLocals,他的类型同Thread内部的threadLocals变量
    image_5c77364a_13aa
    在Thread的init方法中,有一段初始化设置(应该还记得,这个init方法是所有的Thread对象创建的必经之路)
    下面为部分代码片段拼接
    image_5c77364a_2ad4
    从上面的这个方法可以很清晰的看得到
    如果parent的inheritableThreadLocals不是null,那么就会将当前线程的inheritableThreadLocals设置为parent的inheritableThreadLocals
    parent是什么?之前也说过了,就是创建这个线程的线程,也就是平时说的父线程
    所以说
    借助于inheritableThreadLocals,可以实现,创建线程向被创建线程数据传递
    看下下面的方法
    逻辑很清晰,创建了一个ThreadLocalMap
    inheritableThreadLocals就是ThreadLocalMap类型的
    简单理解:这个创建的ThreadLocalMap就是根据入参的ThreadLocalMap,拷贝创建一份
    image_5c77364a_68
    小结:
    Thread对象,通过内部的
        ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    维护从父线程(创建该线程的线程)继承而来的数据
    原理就是在创建线程时,如果当前线程的inheritableThreadLocals不为null,那么将会复制一份保存在自己的ThreadLocal.ThreadLocalMap inheritableThreadLocals中

    InheritableThreadLocal类解析

    对比下 下面的两幅图片,上面为Thread中的相关方法
    下图为InheritableThreadLocal中的三个方法
    很显然,InheritableThreadLocal作为子类,重写了这几个方法
    image_5c77364a_7073
     
    image_5c77364b_73a8
    通过对getMap和createMap方法的重写,可以看得出来,只是内部操作的变量发生了变化,从threadLocals转换为inheritableThreadLocals
    而对于childValue方法,还记得刚才的构造方法么(看注释called only by createInheritedMap)
    也就是说在父线程创建子线程,初始化InheritableThreadLocal时会用到
    image_5c77364b_45a1

    总结

    InheritableThreadLocal的核心概念仍旧是ThreadLocal.ThreadLocalMap以及ThreadLocal
    InheritableThreadLocal是 ThreadLocal的子类
    在Thread内部通过维护    ThreadLocal.ThreadLocalMap inheritableThreadLocals 进行父子线程数据的传递
    而这个数据则是通过在创建Thread对象的时候,借助于内部的init方法,调用createInheritedMap方法,从父线程(当前创建线程)中复制的一份
    后续的数据读取解析,则是通过inheritableThreadLocals变量,与内部的那个threadLocals没有什么关系
    换个思路理解,他就是另外一个ThreadLocal,假定Thread定义了两个“ThreadLocal“,其中一个在创建线程的时候会从父线程复制一份
    只不过从实现上、以及逻辑上,他继承了ThreadLocal而已,然后覆盖了几个方法
     
  • 相关阅读:
    c 语言练习__去掉多余的空白字符_修正
    c 语言练习__求到N的阶乘的和。
    <<c 和指针 >> 部分笔记。
    AsciiDoc Markup Syntax Summary
    gdb 基本命令
    Ubuntu开启防火墙
    转载 jre精简
    windows 下指定jre运行java程序批处理指令
    虚拟机vmware的NAT网络
    liunx 端口权限
  • 原文地址:https://www.cnblogs.com/noteless/p/10448283.html
Copyright © 2020-2023  润新知