ThreadLocal 对有些同学来说可能有点陌生,今天我们就一起来学习一下。
What
ThreadLocal 直译就是「线程本地变量」,意思是 ThreadLocal 中填充的变量属于「当前」线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
How
ThreadLocal 最主要的作用就是线程隔离,在 Android 的消息机制中,很重要的一个角色 Looper,其中每个线程都要有自己的 Looper,这就是通过 ThreadLocal 实现的。直接看代码
用法也是相当的简单,变量最重要的无非就是 Setter 和 Getter . 这样我们就能在任意线程准备好自己的 Looper,也能获取到准备好的 Looper (线程内的单例)。
Why
接下来我们看下这么简单的接口,背后是怎么实现变量在线程间隔离的。
Setter
接下来我们来看下 ThreadLocalMap 又是什么
我们可以看到,这个 ThreadLocalMap 比 HashMap 的实现简单得多,只是简单的通过一个数组来保存 keyValue 的组合 entry,并且在 hash 值计算得出来的 Index 已经有数据时也仅需要简单的找下一个位置即可。另外这个 Hash 值的计算也是非常的简单:
小结一下:
每个 Thread 都有一个 ThreadLocalMap 里面存放了这个 Thread 的所有 ThreadLocal
这个 map 会在 ThreadLocal 设置值的时候去懒加载,再将 ThreadLocal 作为 key 要存的值作为 value 一起放入 map
通过 ThreadLocal 的 hash 值去确定需要 value 放在 Map 的哪个位置
Getter
有了前面的铺垫,我们再来看 Get 方法就轻松了很多
内存泄漏?
我们看到在 ThreadLocalMap.Entry 里,key 是 WeakReference
ThreadLocalMap 的 Setter / Getter 方法中就包含了一些清理已回收的 key 的逻辑
该 key 被回收时,这个 Thread 的生命周期可能也结束了,map 也一起回收了就无所谓泄露了
如果 Thread 生命周期较长,那么我们在使用完 ThreadLocal 时要主动调用 ThreadLocal.remove 方法,即可以在这个线程的 Map 移除对应的 Entry,从而避免泄露
总结
ThreadLocal 的作用是变量的线程隔离,同一个 ThreadLocal 在不同的线程中调用 get 方法会返回不同的 value
Thread 里有一个 ThreadLocalMap,用来存储本线程用到的 ThreadLocal 和 Value,每个线程都有自己的 ThreadLocalMap 就实现了变量线程隔离
ThreadLocalMap 本质上是用一个 Entry 数组来保存数据的,Entry 的 key 是 ThreadLocal 的弱引用,value 就是 ThreadLocal 对象 set 的值
ThreadLocalMap 里通过 ThreadLocal 的 hash 值来计算 Index, 当 index 冲突里继续找下一个可用的 index
ThreadLocal 有可能引起内存泄漏,确认使用结束可以调用 remove 移除相关引用
本文源码基于「Android-28」
领取专属 10元无门槛券
私享最新 技术干货