1

天真地,我期望 ThreadLocal 是某种 Thread 到值类型的 WeakHashMap。所以当我得知 ThreadLocal 的值实际上保存在 Thread 的映射中时,我有点困惑。为什么这样做?如果值保存在 ThreadLocal 本身中,我希望不会存在与 ThreadLocal 相关的资源泄漏。

澄清:我在想类似的东西

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 是值所引用的类上的静态变量时,可能会发生这种情况的最狡猾的形式。现在,由于无法收集对象及其类,因此在应用程序服务器中重新部署时会出现大量资源泄漏。)

4

4 回答 4

8

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

于 2009-12-01T21:32:48.457 回答
4

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

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

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

于 2009-12-01T21:38:44.667 回答
0

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

Anyway, for a variable that each thread should have a slot for, Thread is the natural container of choice. If we could, we would also add our thread local variable directly as a member of Thread class.

于 2009-12-01T22:07:39.723 回答
0

Why would the Map be on ThreadLocal? That doesn't make a lot of sense. So it'd be a Map of ThreadLocals to objects inside a ThreadLocal?

The simple reason it's a Map of Threads to Objects is because:

  1. It's an implementation detail ie that Map isn't exposed in any way;
  2. It's always easy to figure out the current thread (with Thread.currentThread()).

Also the idea is that a ThreadLocal can store a different value for each Thread that uses it so it makes sense that it is based on Thread, doesn't it?

于 2009-12-01T22:51:54.120 回答