alibaba / transmittable-thread-local

📌 a missing Java std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
https://github.com/alibaba/transmittable-thread-local
Apache License 2.0
7.66k stars 1.69k forks source link

能在详细讲解一下replay、restore的设计理念吗?没有思考明白,为什么还需要有恢复步骤 #201

Closed ruanzhi closed 4 years ago

ruanzhi commented 4 years ago

提供反例式的回答

如果直接用map,在capture 时清理map中的数据,同时在restore 清理map中的数据,会有什么影响?

你说的是 map 是指 holder吗?如果是,说明如下:

『在capture 时清理map中的数据』 的问题

ExecutorService executorService = ...

Runnable bizTask = ...
// <doCaptrue>  
// 在capture 时清理Holder中的数据
Runnable ttlRunnable = TtlRunnable.get();

executorService.submit(ttlRunnable);

// 后续运行,因为 Holder 没有KV了,即 后续的传递的内容是空。
// 都不会再正确传递,恢复成空。
// !!Bug!!

Runnable 后续的bizTask = ...
Runnable 后续的ttlRunnable = TtlRunnable.get();

executorService.submit(ttlRunnable);

『在restore 清理map中的数据』 的问题

提交到线程池的任务 可能 在本线程直接执行(参见 CallerRunsPolicy

问题说明如下:

Runnable bizTask = ...
Runnable ttlRunnable = TtlRunnable.get();

// <doRestore>  
// 在restore 清理map中的数据
// 且是 本线程直接执行时,
executorService.submit(ttlRunnable);

// 后续运行,因为 Holder 没有KV了,即 后续的传递的内容是空。
// 都不会再正确传递,恢复成空。
// !!Bug!!

在run 的 finally 中restore 的原因也没想明白,

  1. 如果线程结束了,那么 把之前的 TransmittableThreadLocal restore回来有什么意义?
  2. 线程复用的话,应该是在下次线程执行时复用 启动线程的 TransmittableThreadLocal,而不是restore 的TransmittableThreadLocal。

还是 因为 『提交到线程池的任务 可能 在本线程直接执行』『Restore』确保没有上面的 Bug

按原则的回答

原则:通过 整体流程/设计/代码实现 来 分析/证明 正确性。 @soca2013

CRR(Capture/Replay/Restore)是一个面向上下文传递设计的流程,通过这个流程的分析可以保证/证明 正确性。

这个正确性的分析/证明 ,不依赖于 局部与反例。

总结一下:尽量首先去确定分析自己程序的正确性,而不是找反例。不分析而去依赖反例,又因为经验受限找不到反例认为没问题而上线,这其实就是我们程序出bug的原因。


@soca2013 有说得不明白的地方,欢迎交流。 ❤️

PS

如果你有兴趣『整体流程与分析』推荐:

Originally posted by @oldratlee in https://github.com/alibaba/transmittable-thread-local/issues/145#issuecomment-517914234

ruanzhi commented 4 years ago

我理解直接在在restore里面将holder里面所有的清理掉就OK了,为啥还需要恢复backup。 backup什么情况下才会有值呢?我理解如果是线程池中的线程,backup不可能有值存在。

oldratlee commented 4 years ago

backup什么情况下才会有值呢?

这2个前提成立时,backup往往 不会有值。

当上面2点不成立时,如

这时 backup是有值的,如果不做restore backup业务线程里的上下文就丢了, 业务后续的执行就会有Bug。 @ruanzhi

上面这个线程池场景,因为线程池的广泛大量使用, 是日常业务开发会碰到的问题(在线上,也解决过这样的问题)。

另外,如果用了像Reactive Programming(RP/反应式编程)这样的技术, 业务逻辑 完全是在Reactive接管的 调度器(Scheduler)/线程池 里执行的, 相应的问题出现的可能性就更高了。

ruanzhi commented 4 years ago

『CallerRunsPolicy』情况理解,我再看看 反应式编程,非常感谢

oldratlee commented 4 years ago

@ruanzhi 好,有说的不清楚的,欢迎继续讨论 ♥️

这个Issue先Close了