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

时间:2011-02-19 23:43:16

标签: java multithreading tomcat servlets

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

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

我能做的是实现Filter,并在请求完成后(并将线程返回到池中),使用code from tomcat清除所有ThreadLocal(该方法称为checkThreadLocalsForLeaks)。

问题是,值得吗?两位职业选手:

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

一个骗局:

  • 解决方案使用反射,所以它可能很慢。当然,所有反射数据(Field s)都将被缓存,但仍然存在。

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

3 个答案:

答案 0 :(得分:6)

我会经历向图书馆开发人员报告问题的途径,原因有两个:

  • 这对其他想要使用相同库的人有帮助,但缺乏技能/时间来发现这样一个可怕的内存泄漏。
  • 帮助图书馆的开发者构建更好的产品。

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

作为旁注,我不介意在开发/测试环境中启用该过滤器,并在仍附加ThreadLocal变量时记录严重错误。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

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