天真地,我期望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是值引用的类上的静态变量时,可能会出现最狡猾的形式。现在,在应用程序服务器的重新部署中存在大量资源泄漏,因为无论是对象还是类都不能被收集。)
答案 0 :(得分:8)
有时你只是问一个问题就能得到启发。 :-)现在我刚看到一个可能的答案:线程安全。如果带有值的映射在Thread对象中,则插入新值通常是线程安全的。如果映射在ThreadLocal上,则会出现通常的并发问题,这可能会减慢速度。 (当然你会使用ReadWriteLock而不是同步,但问题仍然存在。)
答案 1 :(得分:4)
您似乎误解了ThreadLocal泄漏的问题。重复使用相同的线程(例如在线程池中)时会发生ThreadLocal泄漏,并且在使用之间不会清除ThreadLocal状态。当Thread被销毁时,它们不是ThreadLocal剩余的结果,因为除了线程本身之外没有任何东西引用ThreadLocal Map。
对线程本地对象使用Thread的弱引用映射不会阻止ThreadLocal泄漏问题,因为线程仍存在于线程池中,因此线程本地对象在从线程重用线程时不适合收集池。您仍然需要手动清除ThreadLocal以避免泄漏。
正如您在答案中所说,并发控制得以简化,ThreadLocal Map是每个线程的单个实例。它还使一个线程无法访问另一个线程的本地对象,如果ThreadLocal对象在您建议的Map上公开了API,则可能不是这种情况。
答案 2 :(得分:0)
我记得几年前Sun将线程局部变量的实现改为当前形式。我不记得它是什么版本以及旧的impl是什么样的。
无论如何,对于每个线程应该有一个插槽的变量,Thread是自然容器的选择。如果可以,我们还将直接添加我们的线程局部变量作为Thread类的成员。
答案 3 :(得分:0)
为什么Map
会在ThreadLocal
上?这没有多大意义。那么它是ThreadLocal中对象的ThreadLocal
s的映射吗?
这是对象Thread
的映射的简单原因是:
Map
不会以任何方式暴露; Thread.currentThread()
)。另外一个想法是ThreadLocal可以为每个使用它的Thread存储不同的值,因此它基于Thread是有意义的,不是吗?