是否值得清除Filter中的ThreadLocals以解决与线程池相关的问题?

简而言之 – tomcat使用线程池,因此线程可以重用。 有些库使用ThreadLocal变量,但不清理它们(使用.remove() ),因此实际上它们会将“脏”线程返回到池中。

Tomcat具有在关闭时检测这些内容以及清除线程本地的新function。 但这意味着线程在整个执行过程中都是“脏”的。

我可以做的是实现一个Filter ,并在请求完成后(并将线程返回到池中),使用tomcat中的代码 (称为checkThreadLocalsForLeaks的方法)清理所有ThreadLocal

问题是,值得吗? 两个优点:

  • 防止内存泄漏
  • 防止库的不确定行为,假设线程是“新鲜的”

一个骗局:

  • 该解决方案使用reflection,因此它可能很慢。 当然,所有reflection数据( Field s)都将被缓存,但仍然如此。

另一种选择是将问题报告给不清除其线程本地的库。

我会通过以下两个原因通过向图书馆开发人员报告问题的途径:

  • 它将有助于其他想要使用相同库的人,但缺乏技能/时间来找到这样一个可怕的内存泄漏。
  • 帮助库的开发人员构建更好的产品。

老实说,我以前从未见过这种类型的错误,我认为这是一个例外,而不是我们应该保护的事情,因为它经常发生。 你能分享一下你见过这种行为的图书馆吗?

作为旁注,我不介意在开发/测试环境中启用该filter,并且如果仍附加ThreadLocal变量则记录严重错误。

从理论上讲,这似乎是一个好主意。 但是,我可以看到一些你可能不想这样做的情况。 例如,一些与xml相关的技术有一些非常重要的设置成本(比如设置DocumentBuilders和Transformers)。 如果你在webapp中做了很多这样的事情 ,那么在ThreadLocals中缓存这些实例可能是有意义的(因为实用程序通常不是线程安全的)。 在这种情况下,您可能不希望在请求之间清除这些。

如果您认为线程的肮脏可能会导致问题,那么这是一件明智的事情。 在可能的情况下应避免出现问题。

使用threadlocals可能是库的不良行为,你当然应该向作者报告,但遗憾的是,现在,由你来处理它。

我不会太担心性能。 reflection中的慢速位是元数据查找; 一旦你有了一个Field对象,那么使用它是相当快的,并且随着时间的推移变得更快 – AIUI,它开始通过对JVM进行本机调用来工作,但经过一些使用后,它会为访问生成字节码,然后可以编译成本机代码,优化,内联等,因此它不应该比直接字段访问慢得多。 我不认为Tomcat代码会跨请求重用Field对象,所以如果你想利用它,你必须编写自己的清理代码。 在任何情况下,性能成本将远远小于与请求关联的IO的成本。