【问题标题】:When the Object referenced by ThreadLocal.ThreadLocalMap.Entry's key is collected by the GC collector [duplicate]当 GC 收集器收集 ThreadLocal.ThreadLocalMap.Entry 的 key 引用的 Object [重复]
【发布时间】:2020-08-25 08:06:56
【问题描述】:

ThreadLocal 经常被用作类静态字段,比如

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

也就是说,userSessionName是一个GC root,即使线程id死了,也永远不会被收集到,直到类被卸载。那么,ThreadLocalMap中的Entry在调用get方法后什么时候会返回null,也就是说ThreadLocalMap.Entry的key什么时候会为null呢?

【问题讨论】:

  • ThreadLocal 本身何时被收集的问题与它的密钥或条目何时被收集的问题无关。
  • tks,我想知道在 ThreadLocalMap 中使用弱引用的含义,当它的关键引用一个静态字段并且线程随着应用程序生命周期保持活动时。

标签: java thread-local


【解决方案1】:

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

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

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


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

ThreadLocalMap 是一个自定义的哈希映射,仅适用于维护线程本地值。在ThreadLocal 类之外没有导出任何操作。该类是包私有的,以允许在类Thread 中声明字段。为了帮助处理非常大且长期存在的使用,哈希表条目使用WeakReferences 作为键。但是,由于不使用引用队列,因此保证只有在表开始空间不足时才会删除陈旧的条目。

这里指的键是WeakReference&lt;ThreadLocal&lt;?&gt;&gt;

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

  • 有足够的内存压力导致WeakReference 中断,并且
  • 具体的ThreadLocalMap 正在获得大量活动。

(“空间不足”注释与代码的作用并不完全一致。它似乎比这更激进。看看代码并下定决心。注意这是依赖于实现行为。)

但无论哪种方式,如果应用程序仍然具有对 ThreadLocal 对象的强可访问引用,则映射中的相应值不会为空……除非应用程序明确执行。

【讨论】:

  • 当线程属于线程池时,对map的引用永远不会被分解。Entry的key总是引用静态的ThreadLocal字段userSessionName,那么,ThreadLocalMap中弱引用的使用是什么意思.
猜你喜欢
  • 1970-01-01
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 2019-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多