java threadlocal 实现_Java的ThreadLocal是如何实现的?

本文深入探讨了ThreadLocal的实现机制,对比了不同实现方式的优劣,详细解析了Java中ThreadLocal如何通过智能设计避免线程争用及内存泄漏问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所有的答案在这里是正确的,但有点失望,因为他们有点晦涩ThreadLocal的实现是多么聪明。我只是看着

source code for ThreadLocal,并令人惊叹的如何实施。

朴素执行

如果我要求你实现ThreadLocal< T>类给定的javadoc中描述的API,你会做什么?初始实现可能是ConcurrentHashMap< Thread,T>使用Thread.currentThread()作为其键。这将工作相当好,但有一些缺点。

>线程争用 – ConcurrentHashMap是一个相当聪明的类,但它最终仍然必须处理防止多个线程以任何方式进行处理,如果不同的线程定期击中,会有减速。

>永久保留一个指向Thread和对象的指针,即使Thread已经完成并且可以被GC’ed。

GC友好实施

确定再试一次,让我们通过使用weak references处理垃圾收集问题。处理WeakReferences可能会令人困惑,但它应该足以使用如下所示的地图:

Collections.synchronizedMap(new WeakHashMap())

或者如果我们使用Guava(我们应该!):

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

这意味着一旦没有其他人持有线程(暗示它已经完成)的关键/值可以被垃圾收集,这是一个改进,但仍然没有解决线程争用问题,意思到目前为止我们的ThreadLocal不是全部那个惊人的类。此外,如果有人决定在Thread对象完成后保持它们,他们永远不会GC,因此我们的对象也不会,即使他们技术上不可达。

聪明的实现

我们一直在考虑ThreadLocal作为线程到值的映射,但也许这不是一个正确的方式来思考它。而不是想象它是一个从Threads到每个ThreadLocal对象中的值的映射,如果我们把它看作一个ThreadLocal对象到每个线程中的值的映射?如果每个线程存储映射,并且ThreadLocal只提供了一个不错的接口到该映射,我们可以避免以前的实现的所有问题。

一个实现看起来像这样:

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

new WeakHashMap()

在这里没有必要担心并发,因为只有一个线程将访问此映射。

Java开发人员在我们这里有一个主要的优势 – 他们可以直接开发Thread类并向其添加字段和操作,这是他们所做的。

06003

其中注释表明,确实是一个包私有映射的所有值由ThreadLocal对象跟踪此线程。 ThreadLocalMap的实现不是一个WeakHashMap,但它遵循相同的基本契约,包括通过弱引用来保持它的键。

ThreadLocal.get()然后实现像这样:

06004

和ThreadLocal.setInitialValue()像这样:

06005

基本上,在这个线程中使用一个地图来保存所有的ThreadLocal对象。这样,我们就不必担心其他Threads中的值(ThreadLocal只能访问当前Thread中的值),因此没有并发问题。此外,一旦线程完成,其地图将自动GC’ed和所有的本地对象将被清理。即使线程被持有,ThreadLocal对象由弱引用持有,并且一旦ThreadLocal对象超出范围就可以被清除。

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

tl; dr ThreadLocal的实现是相当酷,更快/更聪明,比你可能认为乍一看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值