Java的ThreadLocal如何在后台实现?

Java的ThreadLocal如何在后台实现?,第1张

Java的ThreadLocal如何在后台实现?

这里的所有答案都是正确的,但是有些令人失望,因为它们多少掩盖了聪明

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实现。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5615516.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存