Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否值得在筛选器中清理ThreadLocals以解决线程池相关问题?_Java_Multithreading_Tomcat_Servlets - Fatal编程技术网

Java 是否值得在筛选器中清理ThreadLocals以解决线程池相关问题?

Java 是否值得在筛选器中清理ThreadLocals以解决线程池相关问题?,java,multithreading,tomcat,servlets,Java,Multithreading,Tomcat,Servlets,简而言之,tomcat使用线程池,因此线程被重用。有些库使用ThreadLocal变量,但不清理它们(使用.remove()),因此实际上它们会将“脏”线程返回到池中 Tomcat的新特性是在关机时检测这些东西,并清理线程局部。但这意味着线程在整个执行过程中是“脏的” 我所能做的是实现一个过滤器,在请求完成后(线程返回到池中),立即使用清理所有线程本地(该方法称为checkThreadLocalsForLeaks) 问题是,这值得吗?两个优点: 防止内存泄漏 防止假定线程为“新线程”的库出现不

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

Tomcat的新特性是在关机时检测这些东西,并清理线程局部。但这意味着线程在整个执行过程中是“脏的”

我所能做的是实现一个
过滤器
,在请求完成后(线程返回到池中),立即使用清理所有
线程本地
(该方法称为
checkThreadLocalsForLeaks

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

  • 防止内存泄漏
  • 防止假定线程为“新线程”的库出现不确定行为
一个缺点:

  • 该解决方案使用反射,因此速度可能较慢。当然,所有反射数据(
    字段
    s)都将被缓存,但仍然是

另一种选择是将问题报告给不清理线程局部变量的库

我会向库开发人员报告问题,原因有二:

  • 它将帮助其他想要使用同一个库,但缺乏技能/时间来发现如此可怕的内存泄漏的人
  • 帮助库的开发人员构建更好的产品
老实说,我以前从未见过这种类型的错误,我认为这是一个例外,而不是我们应该警惕的事情,因为它经常发生。你能分享一下你在哪个图书馆见过这种行为吗


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

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

如果您认为线程的脏有可能会导致问题,那么这是明智的做法。应尽可能避免出现问题

使用threadlocals可能是图书馆的不良行为,您当然应该向作者报告,但遗憾的是,现在,这要由您来处理


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

即使有一些副作用,我也不认为应该这样滥用。@Bozho,你为什么认为这是滥用?它更像是一个廉价的对象池,因为您永远无法确定给定的库是否能正确地完成所有工作。安全总比后悔好;)这不仅仅是一个图书馆,这是问题所在。清理线程局部变量似乎很少。清理ThreadLocal失败通常不是内存泄漏-例如,如果您使用ThreadLocal,则与线程其余资源占用的空间相比,整数占用的空间可以忽略不计。如果库在每个请求开始时都假定ThreadLocal为空,那么这只是一个问题。我想您可能会感到困惑,我们讨论的不是与存储内容相关的线程本地的大小,而是在卸载web应用程序时它如何产生内存泄漏(整个类加载器)。此外,仅存储一个简单类的场景也不常见。通常,您会有一个框架,比如spring,在线程局部变量中放置一些对象。