首页 > 其他分享 >01-InheritableThreadLocal和TransmittableThreadLocal

01-InheritableThreadLocal和TransmittableThreadLocal

时间:2022-11-27 10:33:34浏览次数:36  
标签:01 Thread THREAD 线程 TransmittableThreadLocal INHERITABLE InheritableThreadLocal 

01-InheritableThreadLocal和TransmittableThreadLocal

1.ThreadLocal存在的问题

public class TheadTest {

    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
    
    /**
     * 当通过父线程创建子线程时,父线程ThreadLocal中的数据不会传递到子线程。
     */
    public static void test01() {
        THREAD_LOCAL.set("123");

        new Thread(() -> {
            System.out.println("==" + THREAD_LOCAL.get()); // ==null
        }).start();

        System.out.println(THREAD_LOCAL.get());
    }
}

2.InheritableThreadLocal

  1. InheritableThreadLocal解决ThreadLocal的问题。
public class TheadTest {

    private static final InheritableThreadLocal<String> INHERITABLE_THREAD_LOCAL = new InheritableThreadLocal<>();

    /**
     * InheritableThreadLocal可以在父线程创建子线程时,将父线程ThreadLocal中的数据拷贝到子线程。
     * 当new Thread()时,InheritableThreadLocal会拷贝线程上下文的数据。
     */
    public static void test02() {
        INHERITABLE_THREAD_LOCAL.set("123");
        new Thread(() -> {
            System.out.println("==" + INHERITABLE_THREAD_LOCAL.get()); // ==123
        }).start();

        System.out.println(INHERITABLE_THREAD_LOCAL.get());
    }
}
  1. InheritableThreadLocal解决ThreadLocal的问题源码分析。

    1. Thread类中有两个ThreadLocal.ThreadLocalMap属性。
    ThreadLocal.ThreadLocalMap threadLocals = null;
    
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    1. 线程本地变量的复制在new Thread()中。
    public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        this(group, target, name, stackSize, null, true);
    }
    
    private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
    
        // 之前代码省略
        
        // inheritThreadLocals是参数传入的值为true。
        // parent.inheritableThreadLocals,在INHERITABLE_THREAD_LOCAL.set("123");时
        // 进行了初始化,所以parent.inheritableThreadLocals != null为true,
        // 程序会进入到if中,将父线程本地变量表的数据拷贝的子线程中。
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        
        // 之后代码省略
    }
    
    1. parent.inheritableThreadLocals初始化部分代码。
    // 执行set()方法时初始化。
    INHERITABLE_THREAD_LOCAL.set("123");
    
    public void set(T value) {
        Thread t = Thread.currentThread();
        // getMap(t)是核心的一段代码。
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }
    
    // InheritableThreadLocal重写了父类ThreadLocal的getMap()方法,所有返回的是
    // Thread类中inheritableThreadLocals。
    ThreadLocalMap getMap(Thread t) {
        return t.inheritableThreadLocals;
    }
    

3.InheritableThreadLocal存在的问题

public class TheadTest {

    private static final InheritableThreadLocal<String> INHERITABLE_THREAD_LOCAL = new InheritableThreadLocal<>();

    /**
     * 打印输出:
     * 456
     * 子线程第一次执行 123
     * 子线程第二次执行 123
     *
     * InheritableThreadLocal在线程池的环境中,当父线程的本地变量表修改之后,
     * 由父线程创建的子线程的本地变量表不会被修改。
     */
    public static void test03() throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1));

        INHERITABLE_THREAD_LOCAL.set("123");
        threadPoolExecutor.execute(() -> {
            System.out.println("子线程第一次执行 " + INHERITABLE_THREAD_LOCAL.get());
        });

        INHERITABLE_THREAD_LOCAL.set("456");
        threadPoolExecutor.execute(() -> {
            System.out.println("子线程第二次执行 " + INHERITABLE_THREAD_LOCAL.get());
        });

        System.out.println(INHERITABLE_THREAD_LOCAL.get());
    }
}

4.TransmittableThreadLocal

  1. 引入依赖。
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.13.2</version>
</dependency>
  1. TransmittableThreadLocal代码事件。
public class TheadTest {
    
    private static final TransmittableThreadLocal<String> TRANSMITTABLE_THREAD_LOCAL = new TransmittableThreadLocal<>();

    /**
     * 打印输出:
     * 456
     * pool-1-thread-1 -> 123
     * pool-1-thread-1 -> 456
     *
     * TransmittableThreadLocal可以解决InheritableThreadLocal在线程池中子线程本地变量表不更新的问题。
     */
    public static void test04() {
        TRANSMITTABLE_THREAD_LOCAL.set("123");

        ExecutorService executorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));
        executorService.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " -> " + TRANSMITTABLE_THREAD_LOCAL.get());
        });

        TRANSMITTABLE_THREAD_LOCAL.set("456");
        executorService.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " -> " + TRANSMITTABLE_THREAD_LOCAL.get());
        });

        System.out.println(TRANSMITTABLE_THREAD_LOCAL.get());
    }
}

标签:01,Thread,THREAD,线程,TransmittableThreadLocal,INHERITABLE,InheritableThreadLocal,
From: https://www.cnblogs.com/godistance/p/16929093.html

相关文章

  • #10115. 「一本通 4.1 例 3」校门外的树
    在区间上种树1.区间[l,r]全部设为一种树木(每次都种新的品种) 2.问[l,r]内有多少种树木且操作不会出现覆盖的情况 把区间当作括号()[],询问时答案为r左边......
  • P3773 [CTSC2017]吉夫特
    发现只要式子中有一个数为奇数,整个式子就为\(0\)。把膜数代到每一乘积项中,容易发现这个东西就是一个\(\text{Lucas}\)定理。卢卡斯定理有一个性质,那就是如果膜数是\(......
  • 2022-2023-1 20221301 《计算机基础与程序设计》第十三周学习总结
    2022-2023-120221301《计算机基础与程序设计》第十三周学习总结作业信息这个作业属于哪个课程<班级的链接>https://edu.cnblogs.com/campus/besti/2022-2023-1-CFA......
  • #10114. 「一本通 4.1 例 2」数星星 Stars
    给定n个点,定义每个点的等级是在该点左下方(含正左、正下)的点的数目,(输入按照y值递增给出)统计每个等级有多少个点 输入按照y值递增给出,y坐标是没有用的(脑补直接求前缀......
  • pwn | pwn2_sctf_2016
    pwn|pwn2_sctf_201632位ret2libc+整数溢出题目给了syscall但是找不到popeax,没办法使。exp如下:frompwnimport*fromLibcSearcher.LibcSearcherimport*impo......
  • Altium Designer Winter 09 — 01 — 快速创建项目
    新建项目 新建原理图导入所需的库添加元器件和接插件连接导线自动标注、修改元件属性编译前——修改项目属性编......
  • 2019红帽杯ctf-reverse-xx
    一道xxtea加密的题主要过程分五步1、读入数据2、构造key数组3、xxtea加密4、打乱数据5、二次加密先查壳,64位无壳直接拖入ida分析  读入数据并计算长度判断......
  • 微服务学习-01_认识微服务
    1、认识微服务1.1常见技术架构1.1.1单体架构单体架构:将业务的所有功能集中在一个项目当中开发,打成一个包来部署优点:架构简单、部署成本低缺点:耦合度高(适用于企......
  • 洛谷P2014 [CTSC1997] 选课
    sloj P2006.「树上背包」选课题目描述在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总......
  • JVM 指令01__加载指令
    一、概述每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧用于存放局部变量表、操作数栈、动态链接、方法出口等信息,在栈帧中与Jvm指令关系最密切的就是局部变量......