TTL篇-TTL的使用

发布时间:2024年01月15日

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传递信息
文章来源:https://blog.csdn.net/qq_27886773/article/details/135600495
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。