有了ThreadLocal为什么要使用TransmittableThreadLocal
先说结论
TransmittableThreadLocal解决的是子线程读取父线程数据的问题。
Child Thread Read Parent Thread Data Locally.
分步讲解
最近在一个项目中发现有如下一行代码:
// 包引用
import com.alibaba.ttl.TransmittableThreadLocal;
private static final ThreadLocal<Long> TENANT_ID = new TransmittableThreadLocal<>();
当时就有一个疑问,为什么不用java自带的TheadLocal而要使用第三方的TransmittableThreadLocal
呢?
换句话说,使用TransmittableThreadLocal
是为了解决什么问题呢?
有时在线程中又创建了子线程,同时子线程有读取父线程数据的需求,就要用到这个类了,看样例:
看样例:
Maven中引入相关包:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.2</version>
</dependency>
使用Java自带的ThreadLocal:
package com.kevinq.myapp;
/**
* @author qww
* 2023/4/18 14:45 */
public class UserThreadLocal {
public void test() throws InterruptedException {
ThreadLocal<String> parentThreadLocal = new ThreadLocal<>();
parentThreadLocal.set("父线程中的数据xxxx");
Thread childThread = new Thread(() -> {
String parentThreadLocalValue = parentThreadLocal.get();
System.out.println("使用ThreadLocal,获取的父线程数据: " + parentThreadLocalValue);
});
childThread.start();
childThread.join();
}
}
使用TransmittableThreadLocal
:
package com.kevinq.myapp;
import com.alibaba.ttl.TransmittableThreadLocal;
/**
* @author qww
* 2023/4/18 14:45 */
public class UseTransmittableThreadLocal {
public void test() throws InterruptedException {
ThreadLocal<String> parentThreadLocal = new TransmittableThreadLocal<>();
parentThreadLocal.set("父线程中的数据xxxx");
Thread childThread = new Thread(() -> {
String parentThreadLocalValue = parentThreadLocal.get();
System.out.println("使用TransmittableThreadLocal,获取的父线程数据:: " + parentThreadLocalValue);
});
childThread.start();
childThread.join();
}
}
main方法启动测试:
package com.kevinq.myapp;
/**
* @author qww
* 2023/4/18 14:43 */
public class TestMain {
public static void main(String[] args) throws InterruptedException {
UserThreadLocal t1 = new UserThreadLocal();
UseTransmittableThreadLocal t2 = new UseTransmittableThreadLocal();
t1.test();
t2.test();
}
}
测试结果:
使用ThreadLocal,获取的父线程数据: null
使用TransmittableThreadLocal,获取的父线程数据:: 父线程中的数据xxxx
如上所示,使用ThreadLocal无法获取父线程的数据,而使用TrnsmittableThreadLocal就可以。
使用场景
异步编程场景下,保证线程池上下文的正确性,如多租户系统中,请求开始时,设置请求信息,租户信息,用户信息等。
原理描述
详细代码层面老实讲,看不太明白,看文字描述吧还是。
TransmittableThreadLocal
时,它实际上是通过 InheritableThreadLocal
和 WeakHashMap
实现线程上下文的传递。
在父线程中,我们将需要传递的变量存储在 TransmittableThreadLocal
中。
- 当子线程创建时,
InheritableThreadLocal
会将父线程中的值复制一份传递给子线程。 - 接着,在子线程中,
TransmittableThreadLocal
会将这些值存储在一个WeakHashMap
中,WeakHashMap
的键是Thread
对象,值是一个ThreadLocalMap
。ThreadLocalMap
用于存储TransmittableThreadLocal
的值,因为ThreadLocalMap
是线程私有的,所以不会出现线程安全的问题。 - 当子线程执行完毕后,
WeakHashMap
会清理掉这个子线程对应的ThreadLocalMap
。这样可以避免出现内存泄漏的问题。
需要注意的是,TransmittableThreadLocal
需要在父线程中设置值后,再创建子线程。因为 InheritableThreadLocal
是在子线程创建时将父线程中的值复制一份,如果在子线程创建后再设置 TransmittableThreadLocal
的值,那么子线程中将无法获取到这些值。
- 点赞
- 收藏
- 关注作者
评论(0)