Java ThreadLocal 相关
Java ThreadLocal.
常见用法
ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).
——ThreadLocal 的 Javdoc
ThreadLocal 的变量通常是 private static
类型的变量。
注意事项
《阿里巴巴 Java 开发手册》中对 ThreadLocal 的使用有如下规定:
【强制】必须回收自定义的 ThreadLocal 变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的 ThreadLocal 变量,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用 try-finally 块进行回收。
正例:
1
2
3
4
5
6 objectThreadLocal.set(userInfo);
try {
// ...
} finally {
objectThreadLocal.remove();
}
【参考】ThreadLocal 对象使用 static 修饰,ThreadLocal 无法解决共享对象的更新问题。
说明:这个变量是针对一个线程内所有操作共享的,所以设置为静态变量,所有此类实例共享此静态变量,也就是说在类第一次被使用时装载,只分配一块存储空间,所有此类的对象(只要是这个线程内定义的)都可以操控这个变量。
ThreadLocal 中有一个内部类 ThreadLocalMap
可能的内存泄漏问题
其实 ThreadLocal
这个类已经考虑到了可能的内存泄漏问题。所以其内部使用到了弱引用。在好几个操作中也会对进行操作防止内存泄漏。
InheritableThreadLocal
ThreadLocal 的一个子类,用于子线程获取父线程的 ThreadLocal 变量。
【并发编程】InheritableThreadLocal使用详解 - 程序员自由之路 - 博客园
讲透 ThreadLocal 和 InheritableThreadLocal - 掘金
InheritableThreadLocal线程池下失效问题解决 - 知乎
当InheritableThreadLocal遇到线程池:主线程本地变量修改后,子线程无法读取到新值_inheritedthreadlocal线程池_快乐崇拜234的博客-CSDN博客
遇到线程池InheritableThreadLocal就废了,该怎么办? - 简书
ThreadLocal垮线程池传递数据解决方案:TransmittableThreadLocal【享学Java】-腾讯云开发者社区-腾讯云
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理 - 掘金
注意事项
slf4j MDCAdapter with multi-thread-context 支持 · Issue #51 · alibaba/transmittable-thread-local
initialValue() 的触发时机
调用 remove 后再调用 get,会再次调用 initialValue()
方法
TransmittableThreadLocal
注意事项
避免线程池创建线程时继承 TransmittableThreadLocal
1 | /** |
方案1:使用 TtlExecutors.getDisableInheritableThreadFactory
,这个可以在创建线程前把当前线程的 TransmittableThreadLocal remove 掉,等创建完线程后再设置回来,从而避免继承。
其他:
Here are some thoughts about the inheritable feature:
case 1
Inheritable feature in thread pooling components(
ThreadPoolExecutor
etc.) should never happen, because threads in thread pooling components is pre-created and pooled, so these threads is neutral for biz logic/data.case 2
Whether the value should be inheritable or not can be controlled by the data owner, disable it carefully when data owner have a clear idea.
disable
inheritable
by overriding thechildValue
and returninitialValue()
:
1
2
3
4
5 TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<String>() {
protected String childValue(String parentValue) {
return initialValue();
}
}
TransmittableThreadLocal会不会有内存泄漏的风险? · Issue #281 · alibaba/transmittable-thread-local
注意事项
注意1:当父线程直接设置 ThreadLocal 为 null 的时候,子线程获取到的可能不是 null,而是 initialValue
对于 set(null) 保持和 InheritableThreadLocal 一致语义? · Issue #157 · alibaba/transmittable-thread-local
相关编码规范
参考资料
- 使用ThreadLocal - 廖雪峰的官方网站
- MemoryLeakProtection - Apache Tomcat【自定义继承了 ThreadLocal 的类可能导致内存泄漏(已修复)】
- 使用ThreadLocal不当可能会导致内存泄露 | 并发编程网
- Java 理论与实践: 用弱引用堵住内存泄漏 - IBM Developer
- 【死磕 Java 并发】—– 深入分析 ThreadLocal - 芋道源码
- ThreadLocal 内存泄露的实例分析
- 深入分析 ThreadLocal 内存泄漏问题
- Java多线程父子线程关系 多线程中篇(六) - noteless - 博客园
- java - Is it really my job to clean up ThreadLocal resources when classes have been exposed to a thread pool? - Stack Overflow