当ThreadLocal.ThreadLocalMap.Entry的键引用的对象被垃圾回收器回收时

huangapple go评论100阅读模式
英文:

When the Object referenced by ThreadLocal.ThreadLocalMap.Entry's key is collected by the GC collector

问题

ThreadLocal通常被用作类的静态字段,就像这样:

public static ThreadLocal<String> userSessionName = new ThreadLocal();

也就是说,userSessionName是一个GC根,即使线程已经结束,它也不会被回收,直到类被卸载。那么,在调用get方法后,ThreadLocalMap中的条目什么时候会返回null?换句话说,ThreadLocalMap中的条目键什么时候会变成null?

英文:

ThreadLocal is often used as a class static filed like

public static ThreadLocal&lt;String&gt; userSessionName = new ThreadLocal();

That is to say, userSessionName is a GC root,and it would never be collected until the class is unloaded even if the thread id dead. So, when will the Entry in ThreadLocalMap return null after calling get method,in other words,when will the ThreadLocalMap.Entry's key be null ?

答案1

得分: 2

一个线程的ThreadLocalMap会在线程存活期间保持可访问。当线程退出时,对映射的引用会被断开;也就是在Thread变得不可访问之前。

只要映射可访问,映射中的条目就是可访问的。可以通过调用ThreadLocal.remove来显式地从映射中移除条目……但这不会自动发生。

(实际上,这并不完全正确。继续阅读。)


在Java 11版本的代码中,以下注释部分部分地解答了您的后续问题:

> ThreadLocalMap是一个定制的哈希映射,仅适用于维护线程本地值。在ThreadLocal类之外不会导出任何操作。该类对包外部是私有的,允许在Thread类中声明字段。为了处理非常大且生命周期长的用法,哈希表条目使用WeakReferences作为键。然而,由于没有使用引用队列,只有在表开始耗尽空间时,才保证会移除陈旧的条目。

这里所指的键是WeakReference<ThreadLocal<?>>

如果应用程序对其ThreadLocal对象有强(普通)引用,任何现存线程的任何映射中的相应值都将被保留。如果应用程序失去对ThreadLocal的(强)引用,那么相应的值可能会被移除。这只会在以下情况下发生:

  • 有足够的内存压力导致WeakReference断开,且
  • 特定的ThreadLocalMap正在得到大量活动。

(“耗尽空间”注释与代码的实际操作并不完全一致。它似乎比这更积极。查看代码并自行判断。请注意,这是实现相关的行为。)

但无论如何,如果应用程序仍然对ThreadLocal对象有强引用,映射中的相应值不会被设置为null……除非应用程序明确这样做。

英文:

A thread's ThreadLocalMap remains reachable as long as the thread is alive. The reference to the map is broken when the thread exits; i.e. before the Thread becomes unreachable.

Entries in the map are reachable as long as the map is reachable. Entries can be removed from the map explicitly by calling ThreadLocal.remove ... but this doesn't happen automatically.

(Actually, this is not entirely correct. Read on.)


The following comments in the Java 11 version of the code partially address your followup question:

> ThreadLocalMap is a customized hash map suitable only for maintaining thread local values. No operations are exported outside of the ThreadLocal class. The class is package private to allow declaration of fields in class Thread. To help deal with very large and long-lived usages, the hash table entries use WeakReferences for keys. However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space.

The keys that this is referring to are WeakReference&lt;ThreadLocal&lt;?&gt;&gt;.

If the application has a strong (i.e. ordinary) reference to its ThreadLocal object, any corresponding values in any map for any extant thread will be kept. If the application loses its (strong) reference to the ThreadLocal, then corresponding values may be removed. This will only occur when:

  • there is sufficient memory pressure to cause the WeakReference to break, AND
  • the specific ThreadLocalMap is getting a lot of activity.

(The "running out of space" comment don't entirely line up with what the code does. It seems to be a bit more aggressive than that. Look at the code and make up your own mind. Noting that this is implementation dependent behavior.)

But either way, if the application still has a strongly reachable reference to a ThreadLocal object, corresponding values in maps won't be nulled ... unless the application does it explicitly.

huangapple
  • 本文由 发表于 2020年8月25日 16:06:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63574561.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定