- 声明的`TransmittableThreadLocal`一般为静态变量; - 或者在`Spring`的`bean`中声明(单例模式)。 `TransmittableThreadLocal`一直被强引用持有。 那么 `holder`即使设计的为`InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>`, 若不在子线程显式调用`remove()`方法,也不会被`GC`回收吧。
Activity
oldratlee commentedon Jun 26, 2021
简单地说:不显式调用
remove()
方法,不被GC
回收,是正确的功能。如果 不调用
remove()
/重新set()
,ThreadLocal
持有的对象被GC
回收, 则是Bug
。 @yexuerui(无故消失,不能正确持有!)
TransmittableThreadLocal
是否强引用一直持有(即如作为static
字段)由业务需求决定。对于
ThreadLocal
(含InheritableThreadLocal
、TransmittableThreadLocal
),一般场景、绝大多数场景下,
static
的方式是合理的;具体需要 使用方 根据业务场景来分析来决定使用方式。
关于内存泄漏
任何持有内存的字段或功能,都会有内存泄漏的风险;需要注意正确使用。
TransmittableThreadLocal
功能本身没有内存泄漏的问题。 @yexuerui即
TransmittableThreadLocal
在正确使用的前提下,业务逻辑不会内存泄漏。相关Issue
oldratlee commentedon Jun 26, 2021
@yexuerui 有涉及出现内存泄漏、具体业务场景下碰到的实际问题吗?
[-]transmittable-thread-local会不会有内存泄漏的风险?[/-][+]TransmittableThreadLocal会不会有内存泄漏的风险?[/+]yexuerui commentedon Jun 26, 2021
因为
TransmittableThreadLocal
继承的是InheritableThreadLocal
,Thread
的init
方法,完成的数据的跨线程传递。(即子线程的
InheritableThreadLocal
的inheritableThreadLocals
会存储值)holder
也是InheritableThreadLocal
变量,在子线程创建时,执行init
方法。子线程的holder
也会继承父线程的值。前提:
TransmittableThreadLocal
的set
方法;remove
方法;InheritableThreadLocal
依旧存在步骤2存入的值。代码验证
local/t4的dubug效果:

也就是在第一次创建
Thread
时,会有些对象无法回收。那么上述,如何清除泄漏的对象呢?
我理解
TransmittableThreadLocal
:在
restoreTtlValues
方法中,会清除子线程设置的holder
和TransmittableThreadLocal
值(用户无需调用remove
方法),但是我想问的是,在线程第一次创建的
holder
如何被清除?我个人理解,普通线程池(非
ForkJoinPool
),且不是CallerRunsPolicy
拒绝策略。子线程调用
remove()
方法,父线程的TransmittableThreadLocal
不会被remove
吧?oldratlee commentedon Jun 26, 2021
1. 关于
Inheritable
能力/功能 (即创建Thread
时的上下文传递)引发的问题上面你讨论的是:
Inheritable
能力/功能 (即创建Thread
时的上下文传递)引发的问题。解决方法 参见 #279 (comment) : @yexuerui
2. 关于
Remove
的时机子线程
remove
/set
操作不应该影响父线程。更进一步表述:ThreadLocal
值在不同线程之间是独立的(这其实是ThreadLocal
的定义和命名)。ThreadLocal
值,这是正确的功能。Inheritable
、Transmittable
。如何实现完成线程传递后的初始化操作 #383 (comment)
线程池 且拒绝策略
CallerRunsPolicy
也会 做remove
。 @yexuerui(
remove
说成restore
,是更合理、严谨的设计)。『也会 做
remove
』原因 简单说明:CRR
操作的上下文的恢复(restore
)操作是在try-finally
的finally
中完成的。更多的说明参见下面的内容:
相关文档与Issue:
CRR
操作)