【发布时间】:2020-10-29 05:31:50
【问题描述】:
我不明白为什么 ThreadLocalMap.Entry 扩展了 WeakReference。
这样做有什么好处?
毕竟,theadlocal.remove() 必须在必要时调用。
如果我们只是将 ThreadLocalMap.Entry 作为一个普通的结构体,比如
{key, value},key是对ThreadLocal的强引用?
【问题讨论】:
标签: java thread-local
我不明白为什么 ThreadLocalMap.Entry 扩展了 WeakReference。
这样做有什么好处?
毕竟,theadlocal.remove() 必须在必要时调用。
如果我们只是将 ThreadLocalMap.Entry 作为一个普通的结构体,比如
{key, value},key是对ThreadLocal的强引用?
【问题讨论】:
标签: java thread-local
想象一下。您在程序中使用线程池。为避免并发错误,您经常使用 ThreadLocal。当一个线程完成任务时,你希望 GC 释放 ThreadLocal 对象。所以在你的线程中将它设置为 null。
好的。现在有两种情况。 A 和 B。
A:假设在 ThreadLocalMap 中有一个对 ThreadLocal 的强引用。 ThreadLocal 对象不会被回收。我们必须等到线程对象被回收后才能回收ThreadLocal对象。然而,坏消息是线程池经常重用已经创建的 Thread 对象,而不是在线程完成其任务后回收它们。结果,我们有越来越多的 ThreadLocal 对象无法回收,直到 JVM 没有更多可用内存并抛出 OutOfMemoryError,我们的程序崩溃。
B:由于Entry继承了WeakReference,所以TreadLocalMap中对ThreadLocal对象的引用是弱引用。当线程完成任务时,我们将线程中ThreadLocal的引用设置为null。此时,ThreadLocal对象在ThreadLocalMap中只有一个弱引用。当GC扫描ThreadLocal对象,发现只有一个弱引用时,忽略弱引用,回收ThreadLocal对象。这就是我们想要的。这就是 Entry 扩展 WeakReference 的原因。
希望我的回答能帮助你更好的理解^_^
【讨论】:
ThreadLocalMap不使用WeakReference作为值,所以如果一个值是一个自定义类,比如static ThreadLocal<CustomClass>,它不会被gc-ed,因为会有成为循环引用。该值将指向它的 ClassLoader,这将是加载您的 App 的加载器,并且由于 ClassLoader 将引用您的 App 及其所有类,因此它不允许 ThreadLocalMap 删除您的静态 ThreadLocal 并且会导致内存泄漏。但是有一个解决方案。