【原创】源码角度分析Android的消息机制系列(二)——ThreadLocal的工作过程

时间:2021-05-08 00:26:37

ι 版权声明:本文为博主原创文章,未经博主允许不得转载。

在上一篇文章中,我们已经提到了ThreadLocal,它并非线程,而是在线程中存储数据用的。数据存储以后,只能在指定的线程中获取到数据,对于其他线程来说是无法获取到数据的,也就是说ThreadLocal可以在多个线程中互不干扰地存储和修改数据。基于ThreadLocal的这一特点,那么当我们在开发中,需要将某些数据以线程作为作用域,并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal了。

Android的消息机制中也用到了ThreadLocal。Handler需要获取到当前线程的Looper,但是不同线程中的Looper是不同的,此时就可以通过ThreadLocal来实现Looper在线程中的存取了。

下面通过例子来观察下ThreadLocal存储数据的特点。

首先定义一个ThreadLocal对象,然后分别在主线程,子线程1和子线程2中设置和访问它的值,代码如下所示:

    private final String TAG=getClass().getSimpleName(); //获取当前类名
private ThreadLocal<Boolean> mBooleanThreadLocal=new ThreadLocal<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mBooleanThreadLocal.set(true);
Log.e(TAG, "[mainThread]mBooleanThreadLocal="+mBooleanThreadLocal.get() ); new Thread("Thread1"){
@Override
public void run() {
super.run();
mBooleanThreadLocal.set(false);
Log.e(TAG, "[Thread1]mBooleanThreadLocal="+mBooleanThreadLocal.get() );
}
}.start(); new Thread("Thread2"){
@Override
public void run() {
super.run();
Log.e(TAG, "[Thread2]mBooleanThreadLocal="+mBooleanThreadLocal.get() );
}
}.start();
}

日志如下所示:

06-17 16:46:04.663 5300-5300/com.bella.androidart E/ThreadLocalActivity: [mainThread]mBooleanThreadLocal=true
06-17 16:46:04.663 5300-5317/com.bella.androidart E/ThreadLocalActivity: [Thread1]mBooleanThreadLocal=false
06-17 16:46:04.679 5300-5318/com.bella.androidart E/ThreadLocalActivity: [Thread2]mBooleanThreadLocal=null

从上面日志可以看出,虽然在不同线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal获取到的值却是不一样的,这就是ThreadLocal的奇妙之处。ThreadLocal之所以有这么奇妙的效果,是因为不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会从各自的线程中取出一个数组,然后再从数组中根据当前ThreadLocal的索引去查找出对应的value值。很显然,不同线程中的数组是不同的。