⛄TransmittableThreadLocal(ttl)

TransmittableThreadLocal

GitHub地址:https://github.com/alibaba/transmittable-thread-local

pom:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.14.2</version>
</dependency>

概要:

1、ThreadLocal 线程隔绝,不能父子线程间传递变量。

2、InheritableThreadLocal,父子线程能传递,但是只在子线程产生时传递(仅一次)。

3、TransmittableTreadLocal,需要规范的使用对应的执行器,才能父子共享同一变量。TtlExecutors.getTtlExecutorService()。

使用场景:

  TransmittableThreadLocal是由阿里开发的一个线程变量传递工具包,解决了InheritableThreadLocal只能再new Thread的时候传递本地变量,无法应用到线程池的问题。可以应用来作链路追踪,传递变量等用途;

在此之前我们可以先了解下JDK中的:ThreadLocalInheritableThreadLocal 

  InheritableThreadLocal 是 Java 中的一个类,它继承自 ThreadLocal 类。ThreadLocal 类是一个用于在多线程环境下管理线程局部变量的工具类,它可以确保在不同线程之间不会共享同一个变量。

而 InheritableThreadLocal 类则提供了额外的特性,它可以将父线程的局部变量自动传递给子线程。

  InheritableThreadLocal 类的主要目的是为了解决在多线程环境下,当一个线程创建了一个 ThreadLocal 变量,而它的子线程需要使用这个变量时,子线程无法获取到父线程的变量值的问题。

为了解决这个问题,InheritableThreadLocal 类提供了一个 getInheritable 方法,它可以将父线程的变量值自动传递给子线程。

简单来说,InheritableThreadLocal 可以实现父子线程之间实现数据传递的功能。

 如何使用:

@SpringBootTest
class SpringbootDemoApplicationTests {

    /**
     * tl
     */
    private static final ThreadLocal<Integer> oldThreadLocal = new ThreadLocal<>();

    /**
     * itl
     */
    private static final InheritableThreadLocal<Integer> itlThreadLocal = new InheritableThreadLocal<>();

    /**
     * ttl
     */
    private static final TransmittableThreadLocal<Integer> ttlThreadLocal = new TransmittableThreadLocal<>();

    @Test
    void itlThread() throws InterruptedException {
        ExecutorService tlExecutorService = Executors.newFixedThreadPool(1);

        oldThreadLocal.set(1);
        System.out.println("oldThreadLocal main线程:" + oldThreadLocal.get()); // 1
        tlExecutorService.execute(() -> System.out.println("oldThreadLocal 子线程:" + oldThreadLocal.get())); // null

        Thread.sleep(100);
        System.out.println("=================itl可以在父子线程中传递值===========================");
        ExecutorService itlExecutorService = Executors.newFixedThreadPool(1);

        itlThreadLocal.set(2);
        System.out.println("itlThreadLocal main线程:" + itlThreadLocal.get()); // 2
        itlExecutorService.execute(() -> System.out.println("itlThreadLocal 子线程:" + itlThreadLocal.get())); // 2

        itlThreadLocal.set(3);
        System.out.println("itlThreadLocal main线程:" + itlThreadLocal.get());// 3
        // 此处使用jdk的线程池,会导致线程复用导致数据串的问题,所以此处获取到的值还是2
        itlExecutorService.execute(() -> System.out.println("itlThreadLocal 子线程:" + itlThreadLocal.get()));// 2
    }

    /**
     * 使用ttl执行器,即使线程复用,也不会导致数据串的问题
     * <p>
     *     为什么使用了ttl,还是会导致数据串的问题?
     * </p>
     */
    @Test
    public void ttlThread() {
        ExecutorService ttlExecutorService = Executors.newFixedThreadPool(1);

        ttlThreadLocal.set(1);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get()); // 1
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get())); // 1

        ttlThreadLocal.set(2);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get()); // 2
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get())); // 1

        ttlThreadLocal.set(3);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get()); // 3
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get())); // 1
    }

    /**
     * 使用ttl执行器,即使线程复用,也不会导致数据串的问题
     * <p>
     *     ttl的使用要搭配ttl线程池来使用,才不会导致数据串的问题
     * </p>
     */
    @Test
    public void ttlThreadFix() {
        ExecutorService ttlExecutorService = Executors.newFixedThreadPool(1);
        // 此处使用了Ttl执行器将线程池包装了一层
        ttlExecutorService = TtlExecutors.getTtlExecutorService(ttlExecutorService);

        ttlThreadLocal.set(1);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get());// 1
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get()));// 1

        ttlThreadLocal.set(2);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get());// 2
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get()));// 2

        ttlThreadLocal.set(3);
        System.out.println("ttlThreadLocal main线程:" + ttlThreadLocal.get());// 3
        ttlExecutorService.execute(() -> System.out.println("ttlThreadLocal 子线程:" + ttlThreadLocal.get()));// 3
    }

}

  

posted @ 2023-12-02 21:22  Java小白的搬砖路  阅读(199)  评论(0编辑  收藏  举报