TTL篇-TTL的使用

本文介绍了TransmittableThreadLocal,它是InheritableThreadLocal的增强版本,解决了线程池中InheritableThreadLocal值不恢复的问题。TTL在任务创建时复制父线程的变量并在任务结束后回滚,适用于分布式跟踪、全链路压测等场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TTL全称TransmittableThreadLocal,是基于InheritableThreadLocal开发的,扩展了InheritableThreadLocal的功能;了解TTL之前,先了解一下InheritableThreadLocal。

官网介绍:Gitee 极速下载/transmittable-thread-local

InheritableThreadLocal

  1.  怎么使用
    1. @Test

          public void testInheritableThreadLocal() {

              InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

              inheritableThreadLocal.set("a");

              ThreadLocal<String> threadLocal = new ThreadLocal<>();

              threadLocal.set("b");

              new Thread(() -> {

                  //a

                  System.out.println(inheritableThreadLocal.get());

                  //null

                  System.out.println(threadLocal.get());

              }).start();

          }

      输出:

      a

      null

  2.  怎么做到的
    1. new Thread()→ init()  → ThreadLocal.createInheritedMap()→ new ThreadLocalMap(); 在线程创建的时候把父对象的inheritableThreadLocals字段拷贝到子对象里面;默认是引用拷贝,可以重写

  3.  结论
    1. InheritableThreadLocal可以在子线程内部使用父线程的变量;满足了变量在父子线程中的传递;
      复制了(浅拷贝)父线程的inheritableThreadLocal到子线程,对于基本变量和字符串修改父线程不会影响到子线程,同理修改子线程不会改变父线程;对于引用对象,就会同时变化
  4.  局限
    1. 现在大多数用的都是线程池,线程只会创建一次;这样的话线程InheritableThreadLocal的值就不会恢复了,各个任务用的是同一个InheritableThreadLocal了
  5. 怎么解决
    1. 使用TTL替代

TransmittableThreadLocal

  1.  怎么使用
    1.     @Test

          public void testTransmittableThreadLocal() throws InterruptedException {

              TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();

              transmittableThreadLocal.set("a");

              ExecutorService executorService = Executors.newFixedThreadPool(2);

              //TTL 干的事情就是在 任务创建的时候用复制此时的父线程的threadLocal,在任务执行完毕后,在回滚回去

              //TTL 对于InheritableThreadLocal的扩充是,InheritableThreadLocal在线程创建的时候,才会拷贝此时父线程的threadLocal, 线程池线程里面同一个线程会有脏数据,这样的话,就不会变化了

              TtlExecutors.getTtlExecutor(executorService).execute(() -> {

                  System.out.println("初始拷贝:" + transmittableThreadLocal.get());

                  TransmittableThreadLocal<String> transmittableThreadLocal1 = new TransmittableThreadLocal<>();

                  transmittableThreadLocal.set("a2");

                  transmittableThreadLocal1.set("c");

                  System.out.println("修改后:" + transmittableThreadLocal.get());

                  System.out.println("子线程本地变量:" +transmittableThreadLocal1.get());

              });

              Thread.sleep(1000);

              TtlExecutors.getTtlExecutor(executorService).execute(() -> {

                  System.out.println("初始拷贝:" + transmittableThreadLocal.get());

              });

              Thread.sleep(1000);

              transmittableThreadLocal.set("a2");

              TtlExecutors.getTtlExecutor(executorService).execute(() -> {

                  System.out.println("父修改后初始拷贝:" + transmittableThreadLocal.get());

              });

              Thread.sleep(Long.MAX_VALUE);

          }

      输出:

      初始拷贝:a

      修改后:a2

      子线程本地变量:c

      初始拷贝:a

      父修改后初始拷贝:a2

  2.  结论
    1. TTL 干的事情就是在任务创建的时候用复制此时的父线程的threadLocal,在任务执行完毕后,在回滚回去

    2. TTL 对于InheritableThreadLocal的扩充是,InheritableThreadLocal在线程创建的时候,才会拷贝此时父线程的threadLocal, 无法用到线程池的场景;但是TransmittableThreadLocal可以在任务创建的时候才会拷贝此时父线程的threadLocal,并且在用完了之后,会再重置到用之前的样子。

  3.  怎么做到的
    1. 需要配合TtlExecutors,TtlRunnable使用;
    2. 在1处进行拷贝,2处进行回滚
  4. ttl使用场景
    1. 分布式跟踪系统 或 全链路压测(即链路打标),
    2. 日志收集记录系统上下文
    3. Session级Cache应用容器或上层框架跨应用代码给下层SDK传递信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值