TransmittableThreadLocal 解决了哪些问题?
Posted Dream_it_possible!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TransmittableThreadLocal 解决了哪些问题?相关的知识,希望对你有一定的参考价值。
目录
一、TransmittableThreadLocal使用场景
二、使用InheritableThreadLocal传递上下文存在的问题
三、TransmittableThreadLocal 解决了哪些问题?
四、如何使用TransmittableThreadLocal?
随着现在应用的分布式以及各种中间件的使用,我们的系统也越来越多的功能和组件涉及到上下文,上下文问题实际上是一个易错的架构问题,因此我们需要统一对业务透明的解决方案。
一、TransmittableThreadLocal使用场景
在使用线程池等会池化复用线程的执行组件情况下,transmittable-thread-local提供ThreadLocal
值的传递功能,解决异步执行时上下文传递的问题
1. 分布式跟踪系统或全链路压测。
2. 日志系统上下文。
3. Session级cache。
4. 应用容器或上层框架应用给下层SDK传递信息。
二、使用InheritableThreadLocal传递上下文存在的问题
1) 每次传递完需要remove操作,如果忘记remove,会出现内存泄漏问题。
2) 传递的时候不小心多remove了一次,那么会出现上下文丢失的问题。
3) InheritableThreadLocal是在父线程创建的时候,将变量复制给子线程,这种方式虽然子线程能继承得到父线程的变量值,但是一般情况下,我们会在多线程环境下使用线程池,线程池会复用之前创建过的线程,不会每用一个线程就创建一个,也就是说这种情况下,子线程可能会得到之前父线程的变量值。
三、TransmittableThreadLocal 解决了哪些问题?
1) 透明且自动完成所有异步执行上下文的捕捉与传递。
2) ttl通过对父线程所在的环境进行拷贝,子线程相当于是继承了父线程的上下文环境, 因此能够与父线程保持一致,ttl解决了InheritableThreadLocal传递变量给子线程出现混乱的问题。
四、如何使用TransmittableThreadLocal?
我们可以通过maven直接添加TTL依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.1</version>
</dependency>
使用TransmittableThreadLocal设置变量:
private static TransmittableThreadLocal<Integer> requestIdTransmittableTheadLocal
= new TransmittableThreadLocal<>();
在给子线程传递变量时用ttl线程池和TransmittablThreadLocal:
private static Executor controlExectutors =
TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(5));
案例演示:
package com.example.future;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.alibaba.ttl.threadpool.TtlExecutors;
import com.example.future.util.ThreadPoolUtil;
import com.example.future.util.threadpolicy.DiscardOldestPolicy;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* @decription:
* @author: zhengbing.zhang
* @date: 2021/7/6 15:01
*/
public class TransmittableThreadLocalDemo {
private static TimeUnit keepAliveTimeUnit = TimeUnit.MINUTES;
private static ExecutorService tomcatExecutors = new ThreadPoolExecutor(8, 16,
60L, keepAliveTimeUnit, new LinkedBlockingDeque<>(100));
// private static ExecutorService controlExecutors = new ThreadPoolExecutor(8, 16,
// 60L, keepAliveTimeUnit, new LinkedBlockingDeque<>(100));
// 使用ttl线程池
private static Executor controlExectutors = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(5));
private static TransmittableThreadLocal<Integer> requestIdTransmittableTheadLocal = new TransmittableThreadLocal<>();
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
tomcatExecutors.submit(new ControlTask(i));
}
tomcatExecutors.shutdown();
}
static class ControlTask implements Runnable {
private int i;
public ControlTask(int i) {
this.i = i;
}
@Override
public void run() {
requestIdTransmittableTheadLocal.set(i);
System.out.println(Thread.currentThread().getName() + ":" + i);
// ttl线程池只有execute()方法
controlExectutors.execute(new BusinessTask(Thread.currentThread().getName()));
}
}
static class BusinessTask implements Runnable {
private String parentThreadName;
public BusinessTask(String parentThreadName) {
this.parentThreadName = parentThreadName;
}
@Override
public void run() {
System.out.println("parentThreadName:" + parentThreadName + ",id: " + requestIdTransmittableTheadLocal.get());
}
}
}
打印结果:
父线程与子线程的变量副本一致 !
参考文献
https://codechina.csdn.net/mirrors/alibaba/transmittable-thread-local
以上是关于TransmittableThreadLocal 解决了哪些问题?的主要内容,如果未能解决你的问题,请参考以下文章
阿里开源TransmittableThreadLocal(TTL)l的使用及原理解析
TransmittableThreadLocal相关组件实用解读,及如何达到线程池中的线程复用,及使用在哪些线程数据传递场景?
每日一博 - ThreadLocal VS InheritableThreadLocal VS TransmittableThreadLocal
TransmittableThreadLocal解决线程池本地变量问题,原来我一直理解错了