来自javadoc
每个线程保持对线程局部变量副本的隐式引用,只要线程是活动的,并且ThreadLocal实例是可访问的;线程消失后,线程本地实例的所有副本都会受到垃圾收集(除非存在对这些副本的其他引用)。
由此看来,只有当线程死掉时,ThreadLocal变量引用的对象才会被垃圾收集。但是,如果ThreadLocal变量a不再被引用并成为垃圾收集的主题,该怎么办?如果保存a的线程仍然存在,那么仅通过变量a进行的对象引用会受到垃圾收集的约束吗?
例如,有以下具有ThreadLocal变量的类:
public class Test {
private static final ThreadLocal a = ...; // references object b
}这个类引用一些对象,而这个对象没有其他引用。然后,在上下文取消部署应用程序时,类加载器成为垃圾收集的主题,但是线程来自线程池,因此不会死。对象b将成为垃圾收集的主题吗?
发布于 2013-06-14 09:51:08
ThreadLocal变量保存在线程中
ThreadLocal.ThreadLocalMap threadLocals;它在当前线程中的第一次ThreadLocal.set/get调用中被延迟初始化,并保存对map的引用,直到Thread激活为止。但是,ThreadLocalMap使用WeakReferences作为键,因此在从其他地方引用ThreadLocal时,可以删除它的条目。有关详细信息,请参阅ThreadLocal.ThreadLocalMap javadoc
发布于 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来清理它们。
发布于 2013-06-14 09:03:50
如果收集ThreadLocal本身是因为它不再是可访问的(引号中有" and“),那么它的所有内容最终都可以被收集,这取决于它是否也被引用到其他地方,以及其他ThreadLocal操作是否发生在同一个线程上,从而触发删除陈旧的条目(例如,参见ThreadLocalMap中的replaceStaleEntry或expungeStaleEntry方法)。ThreadLocal不是线程(强烈)引用的,而是引用线程的:将ThreadLocal<T>看作一个WeakHashMap<Thread, T>。
在您的示例中,如果收集了类加载器,它也将卸载Test类(除非有内存泄漏),并且将收集ThreadLocal a。
https://stackoverflow.com/questions/17104452
复制相似问题