为什么ThreadLocal 选择在线程中使用成员变量,而不是维护一个以线程为Key,值为value的集合?

已经明白了ThreadLocal实现了原理,
但是还是有些疑问,现在的实现是在Thread内维护了一个ThreadLocalMap,
而不是在ThreadLocal里面维护一个map然后用Thread用做Key,需要存的值为value呢?

看见有人说

  1. 这样设计之后每个Map的Entry数量变小了:之前是Thread的数量,现在是ThreadLocal的数量,能提高性能,据说性能的提升不是一点两点

  2. 当Thread销毁之后对应的ThreadLocalMap也就随之销毁了,能减少内存使用量.

第2点觉得还能理解一些,第一点的话为什么可以提高性能呢?
原来的只需要维护一个集合就好了,如果用了现在的实现,虽然维护的Entry数量变少了,但是维护的集合不是变多了吗?难道是因为创建集合消耗的性能更低吗?

还是因为在特殊的环境下,的确会发生需要维护少量Entry性能更高?
在Android开发环境下会遇到这种情况吗?

阅读 4.6k
5 个回答

按照设计来说,ThreadLocal应该依附于Thread的存在而存在,每一个线程都可以有一份空间来存储,所以你说的第2点我非常赞同,至于第1点,我不太看得懂。
如果按照你的设计,将map放在ThreadLocal,那么这个map得是static的(或者ThreadLocal单例中的成员变量),这样在设计上存在严重问题,这个map将非常难以管理:

1. 试想有没有线程安全问题?
2. 线程销毁后怎么处理,不做处理这个map将会越来越大?

设计都有一套方法,甚至有关哲学,得细细品味。

至少我能想到的一点就是:

减少互斥的代价

有一个场景: 为了提升DateFormat的性能, 一般会结合ThreadLocal.

有些设计有时候并不是单纯为了性能,要知道Java是最注重设计模式的,而单一职责是设计模式最重要的原则之一。
反过来说,在ThreadLocal里直接实现一套Map岂不是比直接使用Map更快速度吗,但显然这么做有违单一职责,也使得维护的成本更高。

如果ThreadLoad直接使用Map<Thread, Object>为底层数据结构,当有大量的线程使用ThreadLocal时,首先Map访问的性能会下降,伴随着线程生命周期,底层的Map还需要频繁的添加删除entity,这就很容易造成性能瓶颈。

新手上路,请多包涵

按照这样设计的话,首先会带来线程安全问题,每次set或者get操作时都需要加锁,加锁的话对性能影响就很大了;其次是可见行问题,这意味这任何线程都可以随意查看或修改其他线程的值;当然强行按照这样设计,然后通过其他手段避免上面的两个问题是可以的,只是这样可能又会引起其他新的问题

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题