ThreadLocal简介
ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能在指定的线程中获取存储的数据,对于其他线程来说则是无法获取到的。Looper、ActivityThead以及AMS中都用到了TheadLocal。
TheadLocal的使用场景
一、某些数据是以线程为作用域并且不同线程具有不同的数据副本。比如 Handler,它需要获取当前线程的Looper,Looper的作用域就是线程并且不同线程对应不同的Looper,此时可以通过ThreadLocal实现Looper在线程中的存取。
二、复杂逻辑下的对象传递。比如监听器的传递,采用ThreadLocal可以让监听器作为线程内的全局对象存在,在线程内部可以通过get方法获取到监听器。
ThreadLocal简单使用以及原理分析
首先,举一个简单的例子演示ThreadLocal的使用场景。
![](https://img.haomeiwen.com/i8071313/74e360c8ef75d1ff.png)
分别在主线程以及两个子线程中,设置同一个ThreadLocal对象中值并通过get方法将结果打印出来。
![](https://img.haomeiwen.com/i8071313/fe9e62a16ff218bd.png)
从结果可以得出:虽然在不同线程中访问的是同一个ThreadLocal对象,但是获取到的值却是不同的,那为什么会有这样的结果出现呢?其实是因为ThreadLocal内部会从各自的线程中取出一个数组,再从数组中根据当前ThreadLocal的索引去查找对应的value值,不同的线程中的数组是不同的,这就造成ThreadLocal在不同线程中为维护的数据是互不干扰的。
下面分析ThreadLocal的内部实现,主要从分析其get以及set方法入手。
首先看ThreadLocal的set方法。如图所示:
![](https://img.haomeiwen.com/i8071313/0d3e680ff23c4f39.png)
上面的一段English解释:设置当前线程的本地变量副本。
从源码中可以看出,首先通过getMap方法传递当前线程,返回一个与ThreadLocal相关联的ThreadLocalMap对象,ThreadLocalMap是一个定制的哈希映射,用于维护当前线程中的本地值。如果获取到当前线程中的ThreadLocalMap不是空的话,就设置传入的值,否则创建一个ThreadLocalMap再设置值。
继续跟踪下map.set()方法,如图所示:
![](https://img.haomeiwen.com/i8071313/3b7885733a9c4a6b.png)
其中, ThreadLocalMap.Entry中始终使用ThreadLocal作为键,那table中存储的便是所有的ThreadLocal及其所对应的副本的值,再通过遍历查找到存储ThreadLocal相对应的Entry,设置传入的vaule值。
下面看ThreadLocal的get方法。如图所示:
![](https://img.haomeiwen.com/i8071313/e5b450fabfb3f476.png)
方法解释:返回当前线程中的这个副本的值。
同样先根据当前线程获取到ThreadLocalMap对象,上面谈到过 ThreadLocalMap.Entry中始终使用ThreadLocal作为键,那进而根据当前的ThreadLocal获取到其对应的Entry对象,,获取到其Vaule即可。其中如果获取到的ThreadLocalMap为空,则返回null。
总结
从ThreadLocal的set以及get方法可以看出,他们操作的都是当前线程相关的ThreadLocalMap中存储的Entry对象,所以不同线程中访问同一个ThreadLocal的get和set方法,仅作用于各自线程的内部,因此使用ThreadLocal可以在不同线程中不干扰的读写数据。
参考文献:Android艺术开发探索第十章:ThreadLocal的工作原理。
网友评论