【问题标题】:Why is java.lang.ThreadLocal a map on Thread instead on the ThreadLocal?为什么 java.lang.ThreadLocal 是 Thread 上的映射而不是 ThreadLocal 上的映射?
【发布时间】:2010-12-22 04:35:42
【问题描述】:

天真地,我期望 ThreadLocal 是某种 Thread 到值类型的 WeakHashMap。所以当我得知一个 ThreadLocal 的值实际上是saved in a map in the Thread 时,我有点疑惑。为什么这样做?如果值保存在 ThreadLocal 本身中,我希望与 ThreadLocal 关联的 resource leaks 不会存在。

澄清:我在想类似的东西

public class AlternativeThreadLocal<T> { 
    private final Map<Thread, T> values = 
        Collections.synchronizedMap(new WeakHashMap<Thread, T>());
    public void set(T value) { values.put(Thread.currentThread(), value); }
    public T get() { return values.get(Thread.currentThread());}    
}

据我所知,这将防止出现奇怪的问题,即如果值以某种方式强烈引用 ThreadLocal 本身,则 ThreadLocal 及其剩余值都不会被垃圾收集,直到 Thread 死亡。 (当 ThreadLocal 是值所引用的类上的静态变量时,可能会发生这种情况的最狡猾的形式。现在,由于无法收集对象及其类,因此在应用程序服务器中重新部署时会出现大量资源泄漏。)

【问题讨论】:

    标签: java thread-local resource-leak


    【解决方案1】:

    有时,您只需提出一个问题即可获得启发。 :-) 现在我只看到了一个可能的答案:线程安全。如果具有值的映射位于 Thread 对象中,则插入新值是线程安全的。如果地图在 ThreadLocal 上,您会遇到常见的并发问题,这可能会减慢速度。 (当然你会使用 ReadWriteLock 而不是同步,但问题仍然存在。)

    【讨论】:

      【解决方案2】:

      为什么Map 会出现在ThreadLocal 上?这没有多大意义。所以它会是ThreadLocals 到 ThreadLocal 内对象的映射?

      它是Threads 到对象的映射的简单原因是:

      1. 这是一个实现细节,即Map 不会以任何方式公开;
      2. 找出当前线程总是很容易的(使用Thread.currentThread())。

      还有一个想法是 ThreadLocal 可以为每个使用它的线程存储不同的值,所以它基于 Thread 是有道理的,不是吗?

      【讨论】:

      • 见我的澄清。我认为将其实现为 ThreadLocal 的成员更为自然,但正如我在回答中所讨论的那样,这有缺点。
      【解决方案3】:

      我记得几年前 Sun 将线程局部变量的实现更改为当前形式。我不记得它是什么版本以及旧的 impl 是什么样的。

      无论如何,对于每个线程都应该有一个槽的变量,Thread 是自然选择的容器。如果可以的话,我们也可以直接将我们的线程局部变量添加为 Thread 类的成员。

      【讨论】:

        【解决方案4】:

        您似乎误解了 ThreadLocal 泄漏的问题。 ThreadLocal 泄漏发生在重复使用同一个线程时,例如在线程池中,并且在使用之间没有清除 ThreadLocal 状态。它们不是线程被销毁时剩余的 ThreadLocal 的结果,因为除了线程本身之外没有任何东西引用 ThreadLocal 映射。

        拥有 Thread 到线程本地对象的弱引用映射并不能防止 ThreadLocal 泄漏问题,因为线程仍然存在于线程池中,因此当线程从水池。您仍然需要手动清除 ThreadLocal 以避免泄漏。

        正如您在回答中所说,并发控制得到了简化,ThreadLocal Map 是每个线程的单个实例。它还使一个线程无法访问另一个线程的本地对象,如果 ThreadLocal 对象在您建议的 Map 上公开了 API,则情况可能并非如此。

        【讨论】:

        • 更有害的 ThreadLocal 内存泄漏形式是由值和 ThreadLocal 本身之间的循环引起的。这以微妙的方式发生,例如扩展将 ThreadLocal 声明为成员的类的值。
        • 我确实在考虑 sylvarking 讨论的更成问题的泄漏。至于 API:这可以与当前 API 相同(请参阅我的说明);该地图将被明智的 API 设计者隐藏。 :-)
        猜你喜欢
        • 2010-09-07
        • 2020-09-28
        • 2013-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-05
        • 2017-10-08
        • 1970-01-01
        相关资源
        最近更新 更多