Closed chen-shu-hao closed 2 years ago
TransmittableThreadLocal.holder
的 类型 是 InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>
holder
类型 ThreadLocal<Map<String, String>>
不同。下面假设你说的holder
不是指 TransmittableThreadLocal.holder
,而是你自己业务里的context
。
一般和使用方式相关,主要要注意的可能是
map
跨线程传的引用,会被其它线程修改意料之外的修改。如果用的不是并发安全的map
,还包含了并发Bug。ThreadLocal
初始化是lazy的。来源/父 线程 没有设置过值时(调用ThreadLocal.get()
方法也会触发ThreadLocal.initValue()
设置值),是不会传递的。
子线程会通过ThreadLocal.initValue()
获得值,如果没有重载过返回的是null
。这些方面的问题 理解清楚了,应该是可以构造确定性复现的demo的。 这样并发相关的问题基本上独立于 TTL,只要有并发就要注意并解决好。
下面假设你说的holder
就是指 TransmittableThreadLocal.holder
。
新增map中的key值 会导致原有key对应的value值一定概率丢失为null,出现空指针
TransmittableThreadLocal.holder
这个map 设计实现成: value 只能是 null。
PS: TransmittableThreadLocal.holder
是TTL
的最核心数据,因为有大量的生产环境的使用,有问题的可能性不大。需要了解结合你的使用方式,有更完整的信息,以排查。
无论哪种情况,@chen-shu-hao 给一下 问题的信息:如NPE的栈、你的使用方式、环境 等等
期望能从你这边出这个问题的业务代码中, 请分离整理 一个可以(尽量有较大概率)复现问题的极简可运行Demo工程:❤️
github
工程,这样大家可以用来排查liauraljl/ttl-agent-demo
这个工程否则:
TTL
的问题 还是 业务使用方式问题,都一样值得排查解决掉。 😁holder
是我们项目里的context
,不是您说的TransmittableThreadLocal.holder
。hashmap
,没有使用线程安全的map
。holder
中的map
赋完值后,去子线程中给map
put
了新值。
value
不一致,所以我给一个固定的key
值前面加了当前线程名称作为前缀,企图在接下来的流程中,每个线程取到自己的value
值put
了多次这个key
值后,map
中原有的key
值就出现了value
为null
的情况现在我解决了这个问题:
重新定义了一个新的TransmittableThreadLocal
,没有使用主线程的TransmittableThreadLocal
。
@chen-shu-hao 解决了问题就好。❤️
这个 Issue 先 Close 了。如果还有问题可以继续讨论。
private static TransmittableThreadLocal<Map<String, String>> transmittableThreadLocal = new TransmittableThreadLocal();
子线程修改了transmittableThreadLocal里面某个值, 会透传到主线程里面
private static TransmittableThreadLocal<Map<String, String>> transmittableThreadLocal = new TransmittableThreadLocal(); 子线程修改了transmittableThreadLocal里面某个值, 会透传到主线程里面
是的。缺省传递的是引用。
如果业务有修改并且没恰当的同步,业务这样的通信方式是不线程安全的使用方式,即有 bug。已有不少 issue 讨论过,可以找了看一下。
通过重写TransmittableThreadLocal#copy
方法,可以定制传递方式。
参见项目的用户文档。 @liuyq913
在父子线程情况下
TransmittableThreadLocal<Map<String, String>> holder
新增map
中的key
值时,会导致原有key
对应的value
值一定概率丢失为null
,出现空指针NPE
。