使用了 wrapper 包装器模式包装了 run 方法
为什么要 restore
关注的是 上下文传递流程的规范化。上下文传递到了子线程要做好 清理(或更准确地说是要 恢复 成之前的上下文),需要业务逻辑去处理好。如果业务逻辑对清理的处理不正确,比如:
- 如果清理操作漏了:
- 下一次执行可能是上次的,即『上下文的 污染/串号』,会导致业务逻辑错误。
- 『上下文的 泄漏』,会导致内存泄漏问题。
- 如果清理操作做多了,会出现上下文 丢失。
上面的问题,在业务开发中引发的Bug真是屡见不鲜 !本质原因是:ThreadLocal的set/remove的上下文传递模式 在使用线程池等异步执行组件的情况下不再是有效的。常见的典型例子:
- 当线程池满了且线程池的
RejectedExecutionHandler使用的是CallerRunsPolicy时,提交到线程池的任务会在提交线程中直接执行,ThreadLocal.remove操作清理提交线程的上下文导致上下文丢失。 - 类似的,使用
ForkJoinPool(包含并行执行Stream与CompletableFuture,底层使用ForkJoinPool)的场景,展开的ForkJoinTask会在任务提交线程中直接执行。同样导致上下文丢失。
怎么设计一个『上下文传递流程』方案(即上下文的生命周期),以保证没有上面的问题?
期望:上下文生命周期的操作从业务逻辑中分离出来。业务逻辑不涉及生命周期,就不会有业务代码如疏忽清理而引发的问题了。整个上下文的传递流程或说生命周期可以规范化成:捕捉、回放和恢复这3个操作,即CRR(capture/replay/restore)模式。更多讨论参见 Issue:能在详细讲解一下replay、restore的设计理念吗?#201。
