⛄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中的:ThreadLocal和InheritableThreadLocal ,
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 } }