• ThreadLocal、InheritableThreadLoal、TransmittableThreadLocal使用说明以及适用场景


    ThreadLocal

    ThreadLocal适用场景:

    有状态实例线程安全化、上下文隐式传参

    ThreadLocal以及ThreadLocalMap类图分析

    ThreadLocalMap:key为ThreadLocal,value为需要存放的值。

     

     

     

    ThreadLocal 弱引用

     

    ThreadLocal 内存泄漏问题

    如果ThreadLocalRef置为null,由于只存在弱引用,没有强引用,所以GC会去回收ThreadLocal。因此ThreadLocalMap中key被回收了,value被"遗漏了",导致内存泄漏。

     

    ThreadLocal为什么使用弱引用

     

     

     

    1、ThreadLocal和WeakReference都是在jdk1.2版本引入的。当时没有remove方法,也没有线程池,基本不会发生内存泄漏。

    2、ThreadLocal通过判断key是否为null,对entry进行置换,避免内存泄漏。

    3、Executor框架以及ThreadLocal#remove方法都是在jdk1.5版本引入的。

    InheritableThreadLocal

    1、继承自ThreadLocal,在创建线程的时候实现父子线程之间的参数传递,直接浅拷贝父线程的inheritabeThreadLocals。

    2、jdk1.2版本引入的,不能解决jdk1.5版本引入Executor后线程池的参数传递问题。

     

     

     

    TransmittableThreadLocal

    TransmittableThreadLocal时序图

     

    CRR(capture/replay/restore)设计思想

    1.capture方法:抓取线程(线程A)的所有TTL值。

    2.replay方法:在另一个线程(线程B)中,回放在capture方法中抓取的TTL值,并返回 回放前TTL值的备份

    3.restore方法:恢复线程B执行replay方法之前的TTL值(即备份值)

    TransmittableThreadLocal解决了什么问题,跟InheritableThreadLocal的区别是什么

    InheritableThreadLocal上下文传递时机

    父线程在设置ITL值后,创建子线程时,通过浅拷贝的形式传递给子线程,见InheirtableThreadLocal说明。

    :创建线程时传递ITL值。

    TransmittableThreadLocal上下文传递时机

    父线程在创建任务时将通过抓取当前线程的所有TTL值,在子线程执行任务过程中进行回放。并且在子线程任务执行结束后恢复子线程原来的TTL值。

    为什么要恢复子线程原来的TTL值呢?

    1、线程池设置了CallerRunsPolicy,在线程池触发拒绝策略机制时,任务会由Caller线程执行。如果只是remove掉TTL值的话,会导致Caller线程的上下文丢失。

    2、使用ForkJoinPool的场景,ForkJoinTask会在调用线程中直接执行。

    重点:创建任务时,传递TTL值。

    还原思路跟重放思路类似,这里只分析重放思路。

     

     

     

    TransmittableThreadLocal 使用

    Maven引入

    1. <dependency>
    2. <groupId>com.alibaba</groupId>
    3. <artifactId>transmittable-thread-local</artifactId>
    4. <version>2.11.5</version> //最新版本
    5. </dependency>
    1. public class TransmittableThreadPoolTest {
    2. public static TransmittableThreadLocal<Stu> threadLocal = new TransmittableThreadLocal();
    3. public static ThreadPoolExecutor executorService = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4));
    4. public static void main(String[] args) throws InterruptedException {
    5. threadLocal.set(new Stu(1));
    6. ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(executorService);
    7. // ttlExecutorService = executorService;
    8. for (int i = 0; i < 1; i++) {
    9. ttlExecutorService.execute(new Runnable() {
    10. @Override
    11. public void run() {
    12. System.out.println(threadLocal.get());
    13. }
    14. });
    15. }
    16. Thread.sleep(100);
    17. // threadLocal.set(new Stu(2));
    18. for (int i = 0; i < 1; i++) {
    19. ttlExecutorService.execute(new Runnable() {
    20. @Override
    21. public void run() {
    22. System.out.println(threadLocal.get());
    23. }
    24. });
    25. }
    26. }
    27. }

  • 相关阅读:
    LeetCode75——Day28
    BetaFlight飞控AOCODAF435V2MPU6500固件编译
    解析生成式人工智能 | 它真的有这么强大吗?
    C++之打印编译全过程(二百一十四)
    Boost Efficiency with a Unified App Testing Process
    Vue 3 中,watch 和 watchEffect 的区别
    nginx服务器
    前端工程化:使用 shelljs 生成 yapi 接口文件
    通过API接口进行商品价格监控,可以按照以下步骤进行操作
    企业信息化整体解决方案
  • 原文地址:https://blog.csdn.net/wuweiwoshishei/article/details/126769106