Java的ThreadLocal是如何在引擎盖下实现的?
ThreadLocal是如何实现的?它是用Java实现的(使用从ThreadID到对象的一些并发映射),还是使用一些JVM钩子来更有效地做到这一点?
ThreadLocal是如何实现的?它是用Java实现的(使用从ThreadID到对象的一些并发映射),还是使用一些JVM钩子来更有效地做到这一点?
这里的所有答案都是正确的,但有点令人失望,因为它们在某种程度上掩盖了实现的聪明程度。我只是在查看ThreadLocal
的源代码,并对它的实现方式印象深刻。ThreadLocal
天真的实施
如果我要求你实现一个给定javadoc中描述的API的类,你会怎么做?初始实现可能是使用作为其密钥。这将工作得相当好,但确实有一些缺点。ThreadLocal<T>
ConcurrentHashMap<Thread,T>
Thread.currentThread()
ConcurrentHashMap
GC 友好型实施
好的,再试一次,让我们使用弱引用来处理垃圾回收问题。处理弱引用可能会令人困惑,但是使用这样构建的映射应该就足够了:
Collections.synchronizedMap(new WeakHashMap<Thread, T>())
或者,如果我们使用番石榴(我们应该使用!
new MapMaker().weakKeys().makeMap()
这意味着一旦没有其他人坚持线程(暗示它已完成),键/值可以被垃圾回收,这是一个改进,但仍然没有解决线程争用问题,这意味着到目前为止,我们的类并不是那么神奇。此外,如果有人决定在完成对象后抓住它们,它们永远不会被GC'ed,因此我们的对象也不会,即使它们现在在技术上无法访问。ThreadLocal
Thread
巧妙的实现
我们一直在考虑将线程映射到值,但也许这实际上并不是正确的思考方式。与其将其视为从 Threads 到每个 ThreadLocal 对象中值的映射,不如将其视为 ThreadLocal 对象到每个 Thread 中值的映射呢?如果每个线程都存储映射,并且 ThreadLocal 只是为该映射提供了一个很好的接口,那么我们可以避免以前实现的所有问题。ThreadLocal
实现将如下所示:
// called for each thread, and updated by the ThreadLocal instance
new WeakHashMap<ThreadLocal,T>()
这里无需担心并发性,因为只有一个线程会访问此映射。
Java开发人员在这方面比我们有一个主要的优势 - 他们可以直接开发Thread类并向其添加字段和操作,这正是他们所做的。
在java.lang.Thread
中,有以下几行:
/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;
正如注释所暗示的那样,这确实是对象为此跟踪的所有值的包私有映射。的实现不是 ,但它遵循相同的基本协定,包括通过弱引用来握住其键。ThreadLocal
Thread
ThreadLocalMap
WeakHashMap
ThreadLocal.get()
然后实现如下:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
就像这样:ThreadLocal.setInitialValue()
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
从本质上讲,在此线程中使用映射来保存我们所有的对象。这样,我们就不需要担心其他线程中的值(字面上只能访问当前线程中的值),因此没有并发问题。此外,完成后,其地图将自动进行GC'ed,并且所有本地对象都将被清理。即使 将 保持,对象也会被弱引用保留,并且可以在对象超出范围后立即清理。ThreadLocal
ThreadLocal
Thread
Thread
ThreadLocal
ThreadLocal
毋庸置疑,我对这个实现印象深刻,它非常优雅地解决了许多并发问题(诚然,通过利用作为核心Java的一部分,这是可以原谅的,因为它是一个非常聪明的类),并允许快速和线程安全地访问对象,一次只需要一个线程访问。
tl;博士的实现非常酷,而且比你乍一看想象的要快/聪明得多。ThreadLocal
如果你喜欢这个答案,你也可能喜欢我对ThreadLocalRandom
的(不太详细的)讨论。
Thread
/ThreadLocal
代码片段取自 Oracle/OpenJDK 的 Java 8 实现。
你是说。这很简单,实际上,它只是存储在每个对象中的名称 - 值对的映射(请参阅字段)。API隐藏了实现细节,但这或多或少就是它的全部内容。java.lang.ThreadLocal
Thread
Thread.threadLocals