TTL全称TransmittableThreadLocal,是基于InheritableThreadLocal开发的,扩展了InheritableThreadLocal的功能;了解TTL之前,先了解一下InheritableThreadLocal。
官网介绍:Gitee 极速下载/transmittable-thread-local
InheritableThreadLocal
-
怎么使用
-
@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
-
-
怎么做到的
-
new Thread()→ init() → ThreadLocal.createInheritedMap()→ new ThreadLocalMap(); 在线程创建的时候把父对象的inheritableThreadLocals字段拷贝到子对象里面;默认是引用拷贝,可以重写
-
-
结论
- InheritableThreadLocal可以在子线程内部使用父线程的变量;满足了变量在父子线程中的传递;
复制了(浅拷贝)父线程的inheritableThreadLocal到子线程,对于基本变量和字符串修改父线程不会影响到子线程,同理修改子线程不会改变父线程;对于引用对象,就会同时变化
- InheritableThreadLocal可以在子线程内部使用父线程的变量;满足了变量在父子线程中的传递;
-
局限
- 现在大多数用的都是线程池,线程只会创建一次;这样的话线程InheritableThreadLocal的值就不会恢复了,各个任务用的是同一个InheritableThreadLocal了
-
怎么解决
- 使用TTL替代
TransmittableThreadLocal
-
怎么使用
-
@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
-
-
结论
-
TTL 干的事情就是在任务创建的时候用复制此时的父线程的threadLocal,在任务执行完毕后,在回滚回去
-
TTL 对于InheritableThreadLocal的扩充是,InheritableThreadLocal在线程创建的时候,才会拷贝此时父线程的threadLocal, 无法用到线程池的场景;但是TransmittableThreadLocal可以在任务创建的时候才会拷贝此时父线程的threadLocal,并且在用完了之后,会再重置到用之前的样子。
-
-
怎么做到的
- 需要配合TtlExecutors,TtlRunnable使用;
在1处进行拷贝,2处进行回滚
-
ttl使用场景
- 分布式跟踪系统 或 全链路压测(即链路打标),
- 日志收集记录系统上下文
- Session级Cache应用容器或上层框架跨应用代码给下层SDK传递信息