ThreadLocal 的缺点?

Sherwin.Wei Lv7

ThreadLocal 的缺点?

回答重点

正常情况下使用 ThreadLocal 是没什么问题的,但是如果极端情况下,数据比较多,则可能会出现以下几个问题:

  • 内存泄露问题
  • ThreadLocal 中的 ThreadLocalMap Hash 冲突用的是线性探测法,效率低
  • ThreadLocal 主动清理的开销问题

扩展知识

内存泄漏问题

ThreadLocal 的生命周期和线程的生命周期绑定,线程池中的线程可能被复用,但 ThreadLocal 中的值不会自动清理,导致可能发生内存泄漏。

ThreadLocalMap Hash 冲突

线性探测法,效率低。

68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f79657373696d6964612f63646e5f696d6167652f696d672f32303232303132333136353330372e706e67.png

可以看到,图上显示的是经过两个遍历找到了空位,假设冲突多了,需要遍历的次数就多了。并且下次 get 的时候,hash 直接命中的位置发现不是要找的 Entry ,于是就接着遍历向后找,所以说这个效率低。

而像 HashMap 是通过链表法来解决冲突,并且为了防止链表过长遍历的开销变大,在一定条件之后又会转变成红黑树来查找,这样的解决方案在频繁冲突的条件下,肯定是优于线性探测法,所以这是一个优化方向。

ThreadLocal 主动清理的开销问题

ThreadLocal 使用了 WeakReference 以保证资源可以被释放,但是这可能会产生一些 Etnry 的 key 为 null,即无用的 Entry 存在。

所以调用 ThreadLocal 的 get 或 set 方法时,会主动清理无用的 Entry,减轻内存泄漏的发生

68747470733a2f2f63646e2e6a7364656c6976722e6e65742f67682f79657373696d6964612f63646e5f696d6167652f696d672f32303232303132333136353331362e706e67.png

这其实等于把清理的开销弄到了 get 和 set 上,万一 get 的时候清理的无用 Entry 特别多,那这次 get 相对而言就比较慢了。

Comments