简体   繁体   English

为什么java.lang.ThreadLocal在Thread而不是ThreadLocal上映射?

[英]Why is java.lang.ThreadLocal a map on Thread instead on the ThreadLocal?

Naively, I expected a ThreadLocal to be some kind of WeakHashMap of Thread to the value type. 天真的,我希望ThreadLocal是某种类型的Thread的WeakHashMap到值类型。 So I was a little puzzled when I learned that the values of a ThreadLocal is actually saved in a map in the Thread . 因此,当我得知ThreadLocal的值实际上保存在Thread的映射中时,我感到有些困惑。 Why was it done that way? 为什么这样做呢? I would expect that the resource leaks associated with ThreadLocal would not be there if the values are saved in the ThreadLocal itself. 我希望,如果将值保存在ThreadLocal本身中,则与ThreadLocal相关的资源泄漏将不会在那里。

Clarification: I was thinking of something like 澄清:我在想类似的东西

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());}    
}

As far as I can see this would prevent the weird problem that neither the ThreadLocal nor it's left over values could ever be garbage-collected until the Thread dies if the value somehow strongly references the ThreadLocal itself. 据我所知,这将防止出现一个奇怪的问题,即如果该值以某种方式强烈引用了ThreadLocal本身,则ThreadLocal及其剩余的值都不会被垃圾回收,直到线程死亡。 (Probably the most devious form of this occurs when the ThreadLocal is a static variable on a class the value references. Now you have a big resource leak on redeployments in application servers since neither the objects nor their classes can be collected.) (当ThreadLocal是值引用的类上的静态变量时,这种形式的最vious回形式可能会发生。现在,由于无法收集对象及其类,因此在应用程序服务器中进行重新部署时会出现大量资源泄漏。)

Sometimes you get enlightened by just asking a question. 有时,您只问一个问题便会感到启发。 :-) Now I just saw one possible answer: thread-safety. :-)现在,我只看到一个可能的答案:线程安全。 If the map with the values is in the Thread object, the insertion of a new value is trivially thread-safe. 如果带有值的映射在Thread对象中,则新值的插入对于线程安全而言是微不足道的。 If the map is on the ThreadLocal you have the usual concurrency issues, which could slow things down. 如果映射位于ThreadLocal上,则通常会出现并发问题,这可能会减慢速度。 (Of course you would use a ReadWriteLock instead of synchronize, but the problem remains.) (当然,您将使用ReadWriteLock而不是同步,但是问题仍然存在。)

You seem to be misunderstanding the problem of ThreadLocal leaks. 您似乎误解了ThreadLocal泄漏的问题。 ThreadLocal leaks occur when the same thread is used repeatedly, such as in a thread pool, and the ThreadLocal state is not cleared between usages. 当重复使用同一线程(例如在线程池中)并且在两次使用之间未清除ThreadLocal状态时,会发生ThreadLocal泄漏。 They're not a consequence of the ThreadLocal remaining when the Thread is destroyed, because nothing references the ThreadLocal Map aside from the thread itself. 它们不是销毁Thread时剩下的ThreadLocal的结果,因为除了线程本身之外,没有其他东西引用ThreadLocal Map。

Having a weakly reference map of Thread to thread-local objects would not prevent the ThreadLocal leak problem because the thread still exists in the thread pool, so the thread-local objects are not eligible for collection when the thread is reused from the pool. 具有弱引用的Thread到线程本地对象的引用映射不会防止ThreadLocal泄漏问题,因为线程仍存在于线程池中,因此当从池中重用线程时,线程本地对象不符合收集条件。 You'd still need to manually clear the ThreadLocal to avoid the leak. 您仍然需要手动清除ThreadLocal以避免泄漏。

As you said in your answer, concurrency control is simplified with the ThreadLocal Map being a single instance per thread. 正如您在回答中所说的,并发控制通过ThreadLocal Map(每个线程一个实例)得以简化。 It also makes it impossible for one thread to access another's thread local objects, which might not be the case if the ThreadLocal object exposed an API on the Map you suggest. 这也使一个线程无法访问另一线程的本地对象,如果ThreadLocal对象在您建议的Map上公开了API,则可能不是这种情况。

I remember some years ago Sun changed the implementation of thread locals to its current form. 我记得几年前,Sun将线程本地化的实现更改为当前形式。 I don't remember what version it was and what the old impl was like. 我不记得它是什么版本以及旧的impl是什么样的。

Anyway, for a variable that each thread should have a slot for, Thread is the natural container of choice. 无论如何,对于每个线程都应该有一个插槽的变量,Thread是自然选择的容器。 If we could, we would also add our thread local variable directly as a member of Thread class. 如果可以的话,我们还可以直接将线程局部变量添加为Thread类的成员。

Why would the Map be on ThreadLocal ? 为什么将Map放在ThreadLocal That doesn't make a lot of sense. 那没有什么意义。 So it'd be a Map of ThreadLocal s to objects inside a ThreadLocal? 因此,这将是ThreadLocal到ThreadLocal内部对象的映射?

The simple reason it's a Map of Thread s to Objects is because: 它是Thread到Object的映射的简单原因是:

  1. It's an implementation detail ie that Map isn't exposed in any way; 这是一个实现细节,即Map不会以任何方式公开。
  2. It's always easy to figure out the current thread (with Thread.currentThread() ). 找出当前线程总是很容易的(使用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? 还有一个想法是,ThreadLocal可以为使用它的每个线程存储一个不同的值,这样就可以知道它基于线程,不是吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM