当线程返回线程池后,ThreadLocal对象是否会被清除?

20

当线程返回到线程池时,执行期间存储在ThreadLocal中的内容会自动清除吗(这应该是预期的)?

在我的应用程序中,在某些执行期间将一些数据放入ThreadLocal中,但如果下次使用相同的线程,则会在ThreadLocal存储中找到过时的数据。


5
你不是在回答自己的问题吗?你说:“如果使用相同的线程,那么我会发现过时的数据”。那么,你的问题是什么? - GhostCat
4个回答

17

ThreadLocal和ThreadPool除非你这样做,否则不会相互交互。

你可以创建一个单独的ThreadLocal用于存储所有需要保留的状态,并在任务完成时将其重置。你可以重写ThreadPoolExecutor.afterExecute(或beforeExecute)以清除你的ThreadLocal(s)。

来自ThreadPoolExecutor

/**
 * Method invoked upon completion of execution of the given Runnable.
 * This method is invoked by the thread that executed the task. If
 * non-null, the Throwable is the uncaught {@code RuntimeException}
 * or {@code Error} that caused execution to terminate abruptly.
 *
 * <p>This implementation does nothing, but may be customized in
 * subclasses. Note: To properly nest multiple overridings, subclasses
 * should generally invoke {@code super.afterExecute} at the
 * beginning of this method.
 *
... some deleted ...
 *
 * @param r the runnable that has completed
 * @param t the exception that caused termination, or null if
 * execution completed normally
 */
protected void afterExecute(Runnable r, Throwable t) { }

不必追踪所有的ThreadLocal,你可以一次性清除它们。

protected void afterExecute(Runnable r, Throwable t) { 
    // you need to set this field via reflection.
    Thread.currentThread().threadLocals = null;
}

3
兄弟...如果ThreadPoolExecutor使用了一些线程本地变量,会怎么样? - ZhongYu
1
在企业环境中,通过反射设置(包)受保护字段是一种非法的安全漏洞!:( - MGM
@MGM 只因为你能做某件事,并不意味着你应该这样做。 - Peter Lawrey

16

不行。原则上,将某些东西放入线程本地的人应该负责清除它。

threadLocal.set(...);
try {
  ...
} finally {
  threadLocal.remove();
}

这拯救了我的一天!!这是我代码中缺失的重要部分。 - Karan

3
在执行期间存储在ThreadLocal存储中的内容在线程返回到线程池时会自动清除吗?
不会。ThreadLocal与线程相关联,而不是与传递给线程池任务队列的Callable/Runnable的执行相关联。除非显式清除(@PeterLawrey提供了如何执行此操作的示例),否则ThreadLocal及其状态将通过多个任务执行保留。
看起来您可以通过在Callable/Runnable中声明一个本地变量来实现所需的行为。

2
不,ThreadLocal对象与线程而非任务相关联。因此,在使用线程池时应谨慎使用ThreadLocal。作为原则,只有当ThreadLocal的生命周期与任务的生命周期相一致时,才应在线程池中使用ThreadLocal。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接