线程池上下文参数传递
线程池中的核心线程在执行完任务后不会被销毁,而是回到池中等待下一个任务。当新任务到来时,线程池会分配一个空闲线程来执行。如果这个线程之前执行过某个任务,并且该任务设置了ThreadLocal变量,那么这些变量可能仍然存在于该线程中,导致后续任务访问到旧的数据,或者如果任务没有正确清理ThreadLocal变量,可能导致内存泄漏或数据混乱。
线程池中的线程被重复使用,而不是每次任务都创建新线程。这提高了效率,但也导致线程的ThreadLocal状态在任务之间持续存在。
ThreadLocal变量的生命周期与线程绑定。如果线程被复用,之前设置的变量仍然存在,除非显式清除。
传统做法是在任务执行前设置ThreadLocal变量,但线程池中的任务可能由不同的线程执行,导致主线程设置的ThreadLocal变量在任务线程中不可见。主线程设置ThreadLocal变量后,提交任务到线程池。任务可能在另一个线程执行,该线程的ThreadLocal变量未被设置,导致任务无法获取到主线程的上下文。或者,如果任务执行时设置了ThreadLocal变量,但执行完毕后未清除,后续使用同一线程的任务会看到旧数据。
如果使用ThreadLocal后没有调用remove()方法,线程池中的线程可能长时间存活,导致ThreadLocal关联的对象无法被回收,从而引发内存泄漏。
传统ThreadLocal在线程池中上下文丢失的原因主要是线程复用导致的状态残留和缺乏正确的上下文传递机制。而TTL通过捕获和恢复上下文快照解决了这个问题。
TtlRunnable
和 TtlCallable
是阿里 transmittable-thread-local
工具库的核心类,用于在线程池中实现线程间参数传递。它们通过包装原始任务,在任务提交和执行过程中,自动完成上下文的 捕获、传递、恢复和清理。以下是它们的具体实现逻辑和关键动作:
1. 任务提交时:捕获当前线程的上下文
-
动作:
当使用TtlRunnable.get(task)
或TtlCallable.get(task)
包装任务时,会立即捕获当前线程中所有TransmittableThreadLocal
变量的值,生成一个 上下文快照。 -
实现方式:
通过调用TransmittableThreadLocal.Transmitter.capture()
方法,收集当前线程中所有注册的TransmittableThreadLocal
实例及其值,存储为一个Map<TransmittableThreadLocal<?>, Object>
结构。 -
关键点:
仅捕获TransmittableThreadLocal
的上下文,普通的ThreadLoc