首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ThreadLocal垃圾收集

ThreadLocal垃圾收集
EN

Stack Overflow用户
提问于 2013-06-14 08:40:43
回答 6查看 8.4K关注 0票数 19

来自javadoc

每个线程保持对线程局部变量副本的隐式引用,只要线程是活动的,并且ThreadLocal实例是可访问的;线程消失后,线程本地实例的所有副本都会受到垃圾收集(除非存在对这些副本的其他引用)。

由此看来,只有当线程死掉时,ThreadLocal变量引用的对象才会被垃圾收集。但是,如果ThreadLocal变量a不再被引用并成为垃圾收集的主题,该怎么办?如果保存a的线程仍然存在,那么仅通过变量a进行的对象引用会受到垃圾收集的约束吗?

例如,有以下具有ThreadLocal变量的类:

代码语言:javascript
复制
public class Test {
    private static final ThreadLocal a = ...; // references object b
}

这个类引用一些对象,而这个对象没有其他引用。然后,在上下文取消部署应用程序时,类加载器成为垃圾收集的主题,但是线程来自线程池,因此不会死。对象b将成为垃圾收集的主题吗?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-06-14 09:51:08

ThreadLocal变量保存在线程中

代码语言:javascript
复制
ThreadLocal.ThreadLocalMap threadLocals;

它在当前线程中的第一次ThreadLocal.set/get调用中被延迟初始化,并保存对map的引用,直到Thread激活为止。但是,ThreadLocalMap使用WeakReferences作为键,因此在从其他地方引用ThreadLocal时,可以删除它的条目。有关详细信息,请参阅ThreadLocal.ThreadLocalMap javadoc

票数 8
EN

Stack Overflow用户

发布于 2014-12-17 12:34:38

由此看来,只有当线程死掉时,ThreadLocal变量引用的对象才会被垃圾收集。

这太简单化了。它实际上说的是两件事:

  • 当线程处于活动状态(尚未终止)时,变量的值将不会被垃圾收集,并且ThreadLocal对象是强可达的。
  • 当线程终止时,该值将受普通垃圾收集规则的约束。

还有一个重要的第三种情况,即线程仍然处于活动状态,但ThreadLocal不再具有强可达性。这不是javadoc所涵盖的。因此,在这种情况下,GC行为是未指定的,并且在不同的Java实现中可能会有所不同。

事实上,对于OpenJDK Java 6和OpenJDK Java 8(以及从这些代码基派生出来的其他实现),实际行为相当复杂。线程的线程局部变量的值保存在ThreadLocalMap对象中。评论说:

ThreadLocalMap是一个定制的散列映射,只适用于维护线程本地值。..。为了帮助处理非常大和长期的使用,哈希表条目使用WeakReferences作为密钥。但是,由于不使用引用队列,所以只有在表开始耗尽空间时才保证删除陈旧的条目。

如果您查看代码,在其他情况下也可能删除陈旧的映射条目(带有损坏的WeakReferences)。如果在地图上的get、set、insert或remove操作中遇到陈旧条目,则相应的值将为空。在某些情况下,代码执行部分扫描启发式操作,但唯一可以保证删除所有陈旧映射条目的情况是,调整哈希表的大小(增长)。

所以..。

然后,在上下文取消部署应用程序时,类加载器成为垃圾收集的主题,但是线程来自线程池,因此不会死。对象b将成为垃圾收集的主题吗?

我们能说的最好的就是.取决于应用程序如何管理其他线程,局部变量是所讨论的线程。

所以是的,如果您重新部署一个webapp,陈旧的线程本地映射条目可能是存储漏洞,除非web容器破坏并重新创建线程池中的所有请求线程。(您可能希望web容器能够这样做,但是没有指定AFAIK。)

另一种选择是让您的webapp的Servlets始终在完成每个请求(成功或其他方式)时调用每个服务的ThreadLocal.remove来清理它们。

票数 8
EN

Stack Overflow用户

发布于 2013-06-14 09:03:50

如果收集ThreadLocal本身是因为它不再是可访问的(引号中有" and“),那么它的所有内容最终都可以被收集,这取决于它是否也被引用到其他地方,以及其他ThreadLocal操作是否发生在同一个线程上,从而触发删除陈旧的条目(例如,参见ThreadLocalMap中的replaceStaleEntryexpungeStaleEntry方法)。ThreadLocal不是线程(强烈)引用的,而是引用线程的:将ThreadLocal<T>看作一个WeakHashMap<Thread, T>

在您的示例中,如果收集了类加载器,它也将卸载Test类(除非有内存泄漏),并且将收集ThreadLocal a

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17104452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档