何时以及如何使用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时,最终可能会加载类泄漏。 你需要非常小心地使用ThreadLocalremove()方法清理你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

上一篇: When and how should I use a ThreadLocal variable?

下一篇: Other uses of weak references?