ThreadLocal.ThreadLocalMap.Entry的key引用的Object被GC回收器回收时

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

ThreadLocal 通常用作 class 静态文件,如

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

也就是说,userSessionName是一个GC根,即使线程id死了,也不会在class卸载之前被回收。那么,调用get方法后ThreadLocalMap return中的Entry什么时候为null,也就是ThreadLocalMap.Entry的key什么时候为null?

只要线程处于活动状态,线程的 ThreadLocalMap 就保持可达。当线程退出时,对映射的引用被破坏;即在 Thread 变得无法访问之前。

只要地图可达,地图中的条目就是可达的。可以通过调用 ThreadLocal.remove 明确地从地图中删除条目......但这不会自动发生。

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


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

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.

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

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

  • 内存压力足以导致 WeakReference 中断,AND
  • 具体 ThreadLocalMap 得到很多 activity。

(“运行 out of space”注释与代码的作用并不完全一致。它似乎比那更激进。看看代码和请自行决定。请注意,这是 依赖于实现的 行为。)

但无论哪种方式,如果应用程序仍然具有对 ThreadLocal 对象的强可达引用,映射中的相应值将不会被清空......除非应用程序明确地这样做。