Closed luoxn28 closed 5 years ago
holder中不在captured的先移除,这样会导致当前线程之前set过的TransmittableThreadLocal变量数据丢失,如果父线程中也存在该TransmittableThreadLocal变量但是没set过?
@luoxn28 关于为什么 这样的功能或设计 的 原因,简单说明解释是:
TransmittableThreadLocal
变量虽然存在,但还没有value
,所以 不能/不会传递。
否则系统中所有的一大把的TransmittableThreadLocal
都被传递了。
额外的性能开销问题先不说,更重点的是:传递哪些上下文的,你的实现逻辑 控制不了。
ThreadLocal
的value
是 Lazy Init
(延迟初始化的)。
需要通过 get
/set
操作 完成 ThreadLocal
的value
初始化。
(关于ThreadLocal
延迟初始化,可以了解ThreadLocal
相关的资料)
TL;DR
:)分2部分说明:
ThreadLocal
和 TransmittableThreadLocal
2个类的特性 角度说明ThreadLocal
的特性# 也是InheritableThreadLocal
、TransmittableThreadLocal
的特性,因为这2个本身都是ThreadLocal
(is-a
,子类)。
ThreadLocal
对象本身 一般是static
的。
即ThreadLocal
对象本身一般是全局存在的。ThreadLocal
的value
是 Lazy Init
(延迟初始化的)。
ThreadLocal
在一个线程下有value
了。否则value
还不存在。ThreadLocal
为什么是延迟初始化,这个问题应该是容易理解的,原因是:
在没有具体业务场景前提下,这样的做法避免内存浪费。ThreadLocal
的get
/set
操作 会 初始化 ThreadLocal
的value
。TransmittableThreadLocal
的特性TransmittableThreadLocal
传递的是 TransmittableThreadLocal
的value
。
并不是 TransmittableThreadLocal
对象本身;TransmittableThreadLocal
对象是全局的,本身是不需要传递。ThreadLocal value
的延迟初始化与初始化特性,可以得出:
需要传递场景,就需要显式保证value
已经有了,即初始化了。
(通过调用ThreadLocal
的get
/set
操作完成初始化)。TransmittableThreadLocal#set()
操作。TTL
库完成。TransmittableThreadLocal#get()
操作。set
过,就出现在子线程(更严谨地说,是被传递的线程)』
这其实是 Bug :) @luoxn28如果当前线程holder中有一个
TransmittableThreadLocal
(captured
中没有),并且当前线程之前也set
过该TransmittableThreadLocal
,执行到上述逻辑时,当前线程的TransmittableThreadLocal
变量数据丢失
按上面分析,总结一下:
captured
的值 不能/不应该 传递,否则 是 Bug。
肯定 不期望数据 以不确定的方式 出现在 子线程中。ThreadLocal#set
方法来控制)。并没有 你说的『数据丢失』的问题 :)
看看我解释清楚了吗?欢迎讨论。 @luoxn28 ❤️
谢谢回复~ 你说的这些我是理解的,TTL
代码也是这样实现的。
如果父线程中没
set
过,就出现在子线程(更严谨地说,是被传递的线程)』 这其实是 Bug :)
使用transmittable-thread-local
,是不推荐这种父线程中没有set
过的TransmittableThreadLocal
变量,就出现在被传递线程的。
我当时是看到clean extra TTL value
这块代码时感觉这种场景有问题,实际上不推荐这样使用的~
@luoxn28 实际上不推荐这样使用的
你说得对。❤️
这样的功能或设计,
ThreadLocal#set
方法来控制)』set
过的TransmittableThreadLocal
变量),就出现在被传递线程』这样不期望不确定的效果(Bug
,或说系统行为不确定)。这个Issue 先Close了。 ❤️
您好,看到clean extra TTL value这块逻辑,有个疑问,特请教下,谢谢。
疑问点:
从目前transmittable-thread-local的TtlRunnable实现来看,在TtlRunable run时,会以TtlRunnable.get时间点获取的captured(类似TTL快照)为准,holder中不在captured的先移除,在的会被替换。
holder中不在captured的先移除,这样会导致当前线程之前set过的TransmittableThreadLocal变量数据丢失,如果父线程中也存在该TransmittableThreadLocal变量但是没set过?
这里我有个疑问,如果当前线程holder中有一个TransmittableThreadLocal(captured中没有),并且当前线程之前也set过该TransmittableThreadLocal,执行到上述逻辑时,当前线程的TransmittableThreadLocal变量数据丢失,示例代码如下:
输出结果为:
从目前transmittable-thread-local的TtlRunnable实现来看,在TtlRunable run时,会以TtlRunnable.get时间点获取的captured(类似TTL快照)为准,holder中不在captured的先移除,在的会被替换。这样处理的话,相当于针对TransmittableThreadLocal来说,都是以captured为最高优先级了。
这样来看,TransmittableThreadLocal在TtlRunnable中不像一个ThreadLocal,是一个父线程Transmittable上下文的映射(个人理解),而在普通Runable中才像一个ThreadLocal。
类似issue:https://github.com/alibaba/transmittable-thread-local/issues/90 https://github.com/alibaba/transmittable-thread-local/issues/127