Closed fengzidk closed 2 years ago
TransmittableThreadLocal
是ThreadLocal
/InheritableThreadLocal
。
(aka. TransmittableThreadLocal
是ThreadLocal
/InheritableThreadLocal
的子类。)
目前
TransmittableThreadLocal.set()
方法不允许被重写,如何在不修改源码的前提下实现?
@fengzidk 线程传递的初始化:
override
) 功能直接对应的 扩展方法:
TransmittableThreadLocal#copy(T)
与/或 InheritableThreadLocal#childValue(T)
ThreadLocal#set(T)
方法
ThreadLocal#set(T)
来做初始化操作,因为语义不对应(即系统设计错误),这样的实现方式往往会引发隐晦偶现的业务逻辑Bug!相关的初始化方法还有 [ThreadLocal#initialValue()
](https://docs.oracle.com/javase/10/docs/api/java/lang/ThreadLocal.html#initialValue())。
这3个初始化方法 的区别是 做初始化操作的 生命周期时间点/触发时间 不同:
ThreadLocal#initialValue()
ThreadLocal
没有值时,取值(ThreadLocal#get()
方法)触发初始化。ThreadLocal#initialValue()
是 Lazy的;
即创建ThreadLocal
实例时,并不会触发ThreadLocal#initialValue()
调用。ThreadLocal#set(T)
)再取值,则不会触发调用ThreadLocal#initialValue()
;因为已经有值了。
即使设置的是null
,也不会触发。ThreadLocal#remove()
再取值,会触发调用ThreadLocal#initialValue()
;因为没有值了。InheritableThreadLocal#childValue(T)
InheritableThreadLocal
值。TransmittableThreadLocal#copy(T)
TtlRunnable
)执行中的TransmittableThreadLocal
值。这里可能值得强调一下这3个初始化方法的容易被忽视的地方:3个方法是独立正交的。 (好的系统设计应该这样,不同功能独立正交;系统大的功能 是通过 方便地组合/使用更小的功能 来实现。)
展开一些的说明如下:
InheritableThreadLocal
是ThreadLocal
的子类,包含的ThreadLocal#initialValue()
功能不变。TransmittableThreadLocal
是InheritableThreadLocal
的子类,包含的ThreadLocal#initialValue()
、InheritableThreadLocal#childValue(T)
功能不变。子线程
remove
/set
操作不应该影响父线程。更进一步表述:
ThreadLocal
值在不同线程之间是独立的(这其实是ThreadLocal
的定义和命名)。
- 即 更新操作 不会影响 别的线程的
ThreadLocal
值,这是正确的功能。- 在约定的时机会 传递。
- 这样的传递时机,作为功能 命名成如
Inheritable
、Transmittable
。
在ThreadLocal
的使用中,看到初始化方法的扩展重写没有得到应有的重视与理解使用。
即初始化方法没有重写,结果是在用无业务含义的缺省实现:
ThreadLocal#initialValue()
:返回null
InheritableThreadLocal#childValue(T)
:直接返回入参TransmittableThreadLocal#copy(T)
:直接返回入参这样的做法,导致 上面提到的『通过ThreadLocal#set(T)
方法来完成初始化工作』。结果会导致:
ThreadLocal#set(T)
来,用户使用麻烦/困难。ThreadLocal#set(T)
来做初始化操作,因为语义不对应(即系统设计错误),
这样的实现方式往往会引发隐晦偶现的业务逻辑Bug!写一个示意Demo可以这样;但作为实际系统实现,
TransmittableThreadLocal
便利工具方法TransmittableThreadLocal
提供了下面3个静态工具方法withInitial*
,可以方便地重写这些初始化方法的实现逻辑:
(如果没有静态工具方法withInitial*
,就要写一个TransmittableThreadLocal
子类来重写初始化方法,相对不方便)
withInitial(Supplier)
withInitialAndCopier(Supplier supplier, TtlCopier copierForChildValueAndCopy)
withInitialAndCopier(Supplier supplier, TtlCopier copierForChildValue, TtlCopier copierForCopy)
@fengzidk 具体展开的更多说明,你可以先了解一下ThreadLocal
及其子类。比如看看
TransmittableThreadLocal
的官方文档 User Guide
https://github.com/alibaba/transmittable-thread-localThreadLocal
、InheritableThreadLocal
、TransmittableThreadLocal
的JavaDocTransmittableThreadLocal
的源码如果你用上面的初始化方法不能实现你的需求, 可以贴一下示例代码 并展开说明需求与问题,我们一起看一下 ❤️ @fengzidk
根据业务场景,在线程传递完成后需要进行一些默认的初始化操作 例如: 根据传递的ThreadLocal值 初始化子线程的数据源信息
目前
TransmittableThreadLocal.set()
方法不允许被重写,如何在不修改源码的前提下实现?