Android 进程和线程相关知识点整理
回想起之前有个面试,一面是问一些项目上的问题,包括金融图表绘制啊,包括一些app应用难点,这些因为都做过,所以很轻松的通过了,但是在二面的时候来了个CTO,上来的第一个问题就是进程和线程的区别。
说实话,在这次面试之前,我对这些基础知识点,算是毫无准备。
然后我回想起Android有UI线程和子线程,就说了一句,一个进程可以有多个线程。。。
虽然我之后查阅了不少资料,但是过了这么久,现在只记得:
进程是资源调度的最小单位
线程是任务执行的最小单位
然而在百度里:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。还存在资源开销、包含关系、内存分配、影响关系、执行过程等区别。同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源相互独立。
=。= 算了我反正是懒得看了,但是在我们日常的工作中,除了一些老哥有过AIDL的经验(这里说到IPC进程间通信,就又出现了一个高频知识点了,待会介绍)之外,Android开发中,多线程主要集中在UI线程(主线程),子线程(异步处理耗时任务)中了。
刚刚提到了进程间通信就顺带提一下Linux中的跨进程通信
- 管道 :又分为有名和无名 (无名则才能专心练贱)无名可以让有亲戚关系进程之间通信(父子,爷孙),有名则没有上诉限制,而且都是半双工(发送和接收不能同时进行)
- 信号量:计数器,用于控制多线程对数据的访问,属于一种同步机制
- 信号:通知接收进程某个事件已经发生
- 消息队列:消息链表,存放在内核中,由消息队列标识符标识,UNIX下不同进程之间可实现共享资源的一种机制
- 共享内存:最快的IPC方式(后面再说原因)
- Socket:套接字就不用多说了 C/S 模式
以上是Linux的IPC方式,那Android呢
首先需要知道,为什么Android App开发要用进程间通信:
几年前我在杭州面试过一家做图片直播的公司,除了一些基本问题,就问到了AIDL,在当时我只知道通过IPC确实可以获取到更多的内存资源,而大部分开发人员也确实是想通过IPC来获取更多的内存上限。
而其实我们开发中也常常用到IPC,Activity的Intent可以唤起其他应用,如通讯录,电话,短信。。。
而像广播Broadcast则是可以通知所有程序的IPC,像是电量低等广播
像是Content Provider则给了数据访问的IPC,可以顺利访问到文件或是数据库 (Binder)
Messenger:是基于AIDL实现的C/S 通信(不需要处理多线程)
以上说了这么多,主要核心就两个 AIDL 以及 Binder
AIDL:如果你要对多个应用进行IPC,并且想在服务里处理多线程,用它就是了
Binder:Binder是一种进程间通信机制(我是机制=。=)
- Binder机制有几特点,通过mmap实现了单次数据copy,性能直逼共享内存的方式
- C/S架构,更符合很多场景(相对于共享内存)
- 安全性强于传统IPC,因为传统IPC的安全性,是由上层处理的,而Binder通过进程UID/PID可以区分访问的用户到底是谁,而其他传统IPC则是把信息放在请求数据中,那样就有被篡改的风险。
一不小心说的有点多=。=,回到进程和线程,Android开发中,常用的几个异步线程用法也说一下把:
最常见的情况就是耗时任务是异步的,但是耗时任务结束之后,需要通知页面进行修改,但是页面的绘制又需要在UI线程上
- Handler 在Runnable的run方法中发送消息,在Handler中的handleMessage方法接收消息,并完成ui更新(具体原理说明,网上又无数文章)
- **RxJava **可以通过subscribeOn()和observeOn()在线程间进行切换
- AsyncTask 本人用的比较少,但是看上去易用性挺强的
- ThreadPoolExecutor 线程池
- kotlin协程
由于篇幅问题,这几种的代码明天将进行说明
1.首先是Handler的用法
// Handler就是把UI任务放到handleMessage中执行 hendleMessage则是在sendMessage后会被回调
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
mText.setText("UI操作");
break;
case 2:
mText.setText("UI操作2");
break;
}
}
};
new Thread(new Runnable() {
@Override
public void run() {
// 耗时操作
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
}
}).start();
2.RxJava 实现线程切换
Observable<String> stringOb = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Throwable {
//耗时操作
emitter.onNext("结果");
}
});
stringOb.subscribeOn(Schedulers.io()) // 以上发生在子线程
.observeOn(AndroidSchedulers.mainThread()) // 下面发生在UI线程
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Throwable {
// Ui操作
System.out.println(s);
}
});
3.AsyncTask 实现异步任务
new MyTask().execute();
class MyTask extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... params) {
return "耗时任务结果";
}
@Override
protected void onPostExecute(String s) {
// 更新UI
mText.setText(s);
}
}
4.线程池以后会单独说明(根据阿里Android规范手册中看到的,阿里建议是使用线程池而不是其他方式)
5.kotlin协程
private suspend fun work(): Long {
// work work
return result
}
launch() {
var result = withContext(Dispather.IO){
work()
}
}
launch {
var deferred = async(Dispather.IO) {// 这里做个同步
// 耗时操作
getWebTime()
}
var value = deferred.await()// 这里就会等待上面结果 才会继续执行
}