何时以及如何使用ThreadLocal变量?
什么时候应该使用ThreadLocal
变量?
它是如何使用的?
一种可能的(也是常见的)用法是当你有一些不是线程安全的对象时,但你想避免同步对象的访问(我在看你,SimpleDateFormat)。 相反,给每个线程自己的对象的实例。
例如:
public class Foo
{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date)
{
return formatter.get().format(date);
}
}
文档。
由于ThreadLocal
是给定Thread
内数据的引用,因此在使用线程池的应用程序服务器中使用ThreadLocal
时,最终可能会加载类泄漏。 你需要非常小心地使用ThreadLocal
的remove()
方法清理你get()
或set()
的任何ThreadLocal
。
如果在完成时没有清理,那么对于作为已部署Web应用程序的一部分加载的类的任何引用都将保留在永久堆中,并且永远不会收集垃圾。 重新部署/取消部署webapp不会清除每个Thread
对您的webapp类的引用,因为Thread
不是由您的webapp拥有的。 每个连续的部署将创建一个不会被垃圾收集的类的新实例。
由于java.lang.OutOfMemoryError: PermGen space
而导致的内存不足异常,并且在使用一些Google搜索之后,可能会增加-XX:MaxPermSize
而不是修复该bug。
如果您最终遇到了这些问题,那么您可以通过使用Eclipse的内存分析器和/或遵循Frank Kieviet的指南和跟进来确定哪个线程和类保留了这些引用。
更新:重新发现Alex Vasseur的博客文章,帮助我追踪我遇到的一些ThreadLocal
问题。
许多框架使用ThreadLocals来维护与当前线程相关的一些上下文。 例如,当当前事务存储在ThreadLocal中时,您无需通过每个方法调用将其作为参数传递,以防堆栈中的某人需要访问它。 Web应用程序可能会将有关当前请求和会话的信息存储在ThreadLocal中,以便应用程序可以轻松访问它们。 使用Guice时,可以在为注入对象实现自定义作用域时使用ThreadLocals(Guice的默认servlet作用域最有可能也使用它们)。
ThreadLocals是一种全局变量(尽管稍微不那么邪恶,因为它们仅限于一个线程),所以在使用它们以避免不必要的副作用和内存泄漏时应该小心。 设计您的API,以便在不再需要ThreadLocal值时将自动清除ThreadLocal值,并且不可能正确使用API(例如这样)。 ThreadLocals可以用来使代码更清洁,并且在极少数情况下,它们是使某些工作有效的唯一方式(我当前的项目有两个这样的情况;它们在“静态字段和全局变量”下记录)。
链接地址: http://www.djcxy.com/p/37671.html