Android线程通信机制

Android中的线程通信

前言:

Android开发中我们经常遇到需要切换线程的场景,当进行网络请求,数据库查询(在google新出的jetpack room数据库框架中,强制数据库操作都在新线程上,如果在主线程会抛出异常),文件读写等耗时操作都要新建线程,然后在将结果返回到主线程上。或者想在另一个线程上运行一段代码,这些都是线程间的通信。

但不管你使用何种方式实现:直接使用handle传递信息,使用asynctask,甚至使用rxjava的subscribeon() ,其底层都是通过Android 的handle机制来实现的所以接下来就来探索这一实现过程。

线程共享变量:

刚学过操作系统的我们知道:在同一进程中线程和线程之间资源是共享的,也就是对于任何变量在任何线程都是可以访问和修改的(注意这是在操作系统层面,因为所以线程共用一个进程的资源,但在语言层面,会有局部变量,全局变量的约束,而原则上只要你能找到变量的地址,你就能在任何线程上使用)。
操作系统进程模型

这样一来就好实现了,只需访问所需传递信息的线程的handle就行了,调用handle.send。Android将线程间传递的信息封装成了一个Message类,数据可以传递给Message的object(或复杂一点的bundle字段),调用post()传递代码段其实被封装成了Message的Runnable callback(把代码块当成对象传递)。

线程接收信息

了解了Android线程如何向另一个线程传递信息,那接收信息的线程如何处理呢?,另一个主角looper就要登场了。

1
2
3
4
5
6
7
8
9
10
 (Looper源码)
...
Looper.prepar()
android.os.Handler handler = new Handler(){
@Override
public void handleMessage(final Message msg) {
//这里接受并处理消息
}
};
Looper.loop()

调用这段代码将一个普通线程变成looper线程,looper会不断从其Messagequeue中获取Message传递给这个handle处理(Looper.loop()这个方法其实是个死循环),这个Messagequeue其实是一个阻塞队列,队列中没有东西时会阻塞当前线程。

1
2
3
4
5
6
7
8
looper.loop()主要代码 
for (;;) {
...
Message msg = queue.next();
...
msg.target.dispatchMessage(msg);
...
}

线程本地变量

那么如何根据不同的thread获取其自己的looper呢?这就要用到ThreadLocal了。
ThreadLocal,顾名思义,就是线程的本地变量,他将变量和线程联系起来,是不同线程获取不同的值。其实这个实现很简单一点也不神秘,只是做了一些封装,用起来很方便,用在looper上
(至于如何获取当前运行的线程,其实底部是通过native C语言方法来实现的)

1
2
3
4
5
6
7
8
9
10
 (Looper源码)
...
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
...

想获取只需
sThreadLocal.get()(将本身ThreadLocal<Looper>作为map的键)

Thread里面有一个map:
ThreadLocal.ThreadLocalMap threadLocals

这样就可以实现线程间的通信了!
而rxjava的各种操作符,asyncTask底部都是通过这个来实现的!
另外就不得不提到kotlin的协程了

协程:就是一个线程框架,就是 Kotlin 提供的一套线程封装的 API——扔物线

kotlin的协成比rxjava等其他封装的更好,功能更强大,更方便,推荐大家去学习!

,
© 2020 WPY's Android Tour All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero