你们用 ThreadLocal 传用户信息或 traceId 吗?线程池复用时怎么避免数据串号和内存泄漏?
我的判断
ThreadLocal 适合在同一线程调用链传递少量上下文,但线程池复用前必须清理,异步跨线程时还要显式传播。
Web 请求进入时可以放用户 ID 或 traceId,最外层过滤器必须用 try/finally:
try {
RequestContext.set(context);
chain.doFilter(request, response);
} finally {
RequestContext.clear();
}
线程池线程会服务下一位用户,不 remove 就可能串号;value 还可能被线程长期引用,形成内存泄漏。上下文里只放标识,不放大 DTO、连接或可变集合。
提交到另一个线程池后,原 ThreadLocal 不会自动过去。我会用任务装饰器在提交时复制必要字段、执行前安装、结束后恢复和清理;链路追踪优先采用 OpenTelemetry/MDC 已有的上下文机制。
使用 InheritableThreadLocal 也不是通用修复,池中线程早已创建,而且复用时仍有污染问题。
容易答偏踩坑误区
- 只调用 set,不在 finally remove。 异常路径最容易留下脏上下文。
- 把 ThreadLocal 当跨线程消息总线。 异步、响应式和虚拟线程边界都需要重新审视。
- 保存重量对象。 线程生命周期通常比请求长得多。