当类已公开到线程池时,清理 ThreadLocal 资源真的是我的工作吗?我对 ThreadLocal 的使用雄猫如何鞭打谁该责怪谁?但是该怎么办呢?叹息,这是旧闻一些教训对库实施者的影响选择引导注释
我对 ThreadLocal 的使用
在我的Java类中,我有时会主要使用a作为避免不必要的对象创建的手段:ThreadLocal
@net.jcip.annotations.ThreadSafe
public class DateSensitiveThing {
private final Date then;
public DateSensitiveThing(Date then) {
this.then = then;
}
private static final ThreadLocal<Calendar> threadCal = new ThreadLocal<Calendar>() {
@Override
protected Calendar initialValue() {
return new GregorianCalendar();
}
};
public Date doCalc(int n) {
Calendar c = threadCal.get();
c.setTime(this.then):
// use n to mutate c
return c.getTime();
}
}
我这样做是出于适当的理由 - 是那些光荣的状态,可变的,非线程安全的对象之一,它提供跨多个调用的服务,而不是表示值。此外,实例化被认为是“昂贵的”(这是否属实不是这个问题的重点)。(总的来说,我真的很佩服它:-))GregorianCalendar
雄猫如何鞭打
但是,如果我在任何池化线程的环境中使用这样的类 - 并且我的应用程序无法控制这些线程的生命周期 - 那么就有可能发生内存泄漏。Servlet 环境就是一个很好的例子。
事实上,当Web应用程序停止时,Tomcat 7会像这样呜呜呜:
SEVERE:Web 应用程序 [] 创建了一个 ThreadLocal,其密钥类型为 [org.apache.xmlbeans.impl.store.CharUtil$1](值 [org.apache.xmlbeans.impl.store.CharUtil$1@2aace7a7])和类型为 [java.lang.ref.SoftReference](值 [java.lang.ref.SoftReference@3d9c9ad4]),但在 Web 应用程序停止时未能将其删除。随着时间的推移,线程将更新,以尝试避免可能的内存泄漏。Dec 13, 2012 12:54:30 PM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
(在这种特殊情况下,甚至我的代码也没有这样做)。
谁该责怪谁?
这似乎不公平。Tomcat指责我(或我班级的用户)做了正确的事情。
最终,这是因为Tomcat希望重用它提供给我的线程,用于其他Web应用程序。也许,对于Tomcat来说,这不是一个很好的策略 - 因为线程实际上确实具有/导致状态 - 不会在应用程序之间共享它们。
但是,这种政策至少是常见的,即使它是不可取的。我觉得我有义务 - 作为用户,为我的类提供一种“释放”我的类附加到各种线程的资源的方法。ThreadLocal
但是该怎么办呢?
在这里做什么是正确的?
对我来说,servlet引擎的线程重用策略似乎与背后的意图不一致。ThreadLocal
但也许我应该提供一个工具,允许用户说“begone,邪恶的线程特定状态与这个类相关联,即使我没有资格让线程死亡并让GC做它的事情?我有可能这样做吗?我的意思是,我并不需要安排在过去某个时候看到的每个线程上被调用。还是有其他方法?ThreadLocal#remove()
ThreadLocal#initialValue()
或者我应该对我的用户说“去给自己买一个体面的类加载器和线程池实现”?
编辑#1:澄清了如何在不知道线程生命周期的vanailla实用程序类中使用 编辑#2:修复了线程安全问题threadCal
DateSensitiveThing