java threadlocal 缺点_Java的ThreadLocal如何在后台实现?

小编典典

这里的所有答案都是正确的,但是有些令人失望,因为它们多少掩盖了聪明ThreadLocal的实现是多么的明智。我只是在寻找源代码,ThreadLocal并且对它的实现方式印象深刻。

天真的实现

如果我要求您ThreadLocal在javadoc中描述的给定API的基础上实现一个类,该怎么办?最初的实现可能是ConcurrentHashMap使用Thread.currentThread()作为其密钥。这样会很好地工作,但确实有一些缺点。

线程争用- ConcurrentHashMap是一个非常聪明的类,但是它最终仍必须处理防止多个线程以任何方式破坏它,并且如果不同的线程有规律地命中它,将会降低速度。

即使在线程完成并且可以进行GC处理后,它仍永久保持指向线程和对象的指针。

GC友好的实现

好的,再试一次,让我们使用弱引用来处理垃圾回收问题。处理WeakReferences可能会造成混淆,但是使用像这样构建的地图应该足够了:

Collections.synchronizedMap(new WeakHashMap())

或者,如果我们使用的是番石榴(应该是!):

new MapMaker().weakKeys().makeMap()

这意味着一旦没有其他人抓住线程(暗示线程已完成),就可以对键/值进行垃圾收集,这是一种改进,但仍无法解决线程争用问题,这意味着到目前为止,我们ThreadLocal还不是全部令人赞叹的一堂课。此外,如果有人决定在Thread完成后保留对象,那么就永远不会对它们进行GC处理,因此即使我们的对象现在在技术上无法到达,也不会对其进行GC处理。

聪明的实现

我们一直在考虑ThreadLocal将线程映射为值,但是也许这实际上并不是正确的思考方式。与其将其视为从Threads到每个ThreadLocal对象中的值的映射,不如将其视为ThreadLocal对象到

每个Thread中的

值的映射怎么办?如果每个线程都存储了该映射,而ThreadLocal仅提供了该映射的一个不错的接口,我们可以避免以前实现中的所有问题。

一个实现看起来像这样:

// called for each thread, and updated by the ThreadLocal instance

new WeakHashMap()

此处无需担心并发性,因为只有一个线程将访问此映射。

Java开发人员在这里比我们有一个主要优势-他们可以直接开发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;

}

本质上, 在此线程中

使用地图可以容纳我们所有的ThreadLocal对象。这样,我们永远不必担心其他线程中的值(ThreadLocal字面上只能访问当前线程中的值),因此没有并发问题。此外,一旦Thread完成,其映射将自动进行GC处理,并且将清除所有本地对象。即使将Thread其保留,ThreadLocal对象也会被弱引用保留,并且一旦ThreadLocal对象超出范围,就可以将其清除。

不用说,这个实现给我留下了深刻的印象,它很好地解决了很多并发问题(可以利用作为核心Java的一部分,但这是可以原谅的,因为它是一个非常聪明的类),并且允许快速和对仅一次需要一个线程访问的对象的线程安全访问。

tl; dr ThreadLocal的实现非常酷,并且比您乍看之下要快/聪明得多。

如果您喜欢这个答案,您可能也会喜欢我(不那么详细)的讨论ThreadLocalRandom。

2020-09-15

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值