这里的所有答案都是正确的,但是有些令人失望,因为它们多少掩盖了聪明
ThreadLocal的实现是多么的明智。我只是在寻找源代码,
ThreadLocal并且对它的实现方式印象深刻。
天真的实现
如果我要求您
ThreadLocal<T>在javadoc中描述的给定API的基础上实现一个类,该怎么办?最初的实现可能是
ConcurrentHashMap<Thread,T>使用
Thread.currentThread()作为其密钥。这样会很好地工作,但确实有一些缺点。
- 线程争用-
ConcurrentHashMap
是一个非常聪明的类,但是它最终仍必须处理防止多个线程以任何方式破坏它,并且如果不同的线程有规律地命中它,将会降低速度。 - 即使在线程完成并且可以进行GC处理后,它仍永久保持指向线程和对象的指针。
GC友好的实现
好的,再试一次,让我们使用弱引用来处理垃圾回收问题。处理WeakReferences可能会造成混淆,但是使用像这样构建的地图应该足够了:
Collections.synchronizedMap(new WeakHashMap<Thread, T>())
或者,如果我们使用的是番石榴(应该是!):
new MapMaker().weakKeys().makeMap()
这意味着一旦没有其他人抓住线程(暗示线程已完成),就可以对键/值进行垃圾收集,这是一种改进,但仍无法解决线程争用问题,这意味着到目前为止,我们
ThreadLocal还不是全部令人赞叹的一堂课。此外,如果有人决定在
Thread完成后保留对象,那么就永远不会对它们进行GC处理,因此即使我们的对象现在在技术上无法到达,也不会对其进行GC处理。
聪明的实现
我们一直在考虑
ThreadLocal将线程映射为值,但是也许这实际上并不是正确的思考方式。与其将其视为从Threads到每个ThreadLocal对象中的值的映射,不如将其视为ThreadLocal对象到
每个Thread中的
值的映射怎么办?如果每个线程都存储了该映射,而ThreadLocal仅提供了该映射的一个不错的接口,我们可以避免以前实现中的所有问题。
一个实现看起来像这样:
// called for each thread, and updated by the ThreadLocal instancenew WeakHashMap<ThreadLocal,T>()
此处无需担心并发性,因为只有一个线程将访问此映射。
Java开发人员在这里比我们有一个主要优势-他们可以直接开发Thread类并向其添加字段和 *** 作,而这正是他们所做的。
其中
java.lang.Thread有以下几行:
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;}
本质上, 在此线程中
使用地图可以容纳我们所有的
ThreadLocal对象。这样,我们永远不必担心其他线程中的值(
ThreadLocal字面上只能访问当前线程中的值),因此没有并发问题。此外,一旦
Thread完成,其映射将自动进行GC处理,并且将清除所有本地对象。即使将
Thread其保留,
ThreadLocal对象也会被弱引用保留,并且一旦
ThreadLocal对象超出范围,就可以将其清除。
不用说,这个实现给我留下了深刻的印象,它很好地解决了很多并发问题(可以利用作为核心Java的一部分,但这是可以原谅的,因为它是一个非常聪明的类),并且允许快速和对仅一次需要一个线程访问的对象的线程安全访问。
tl; dr
ThreadLocal的实现非常酷,并且比您乍看之下要快/聪明得多。
如果您喜欢这个答案,您可能也会喜欢我(不那么详细)的讨论
ThreadLocalRandom。
Thread/
ThreadLocal代码段摘自Oracle / OpenJDK的Java
8实现。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)