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
}
}