Android thread
本片文章将介绍android的线程相关知识,主要分为三个部分:背景知识、线程种类以及各自的适用场景,文章摘自efficient android threading
一、背景知识
说到线程,我们首先知道需要讲进程,因为线程属于进程内部的东西,在android中,进程是怎样的设计?进程和应用又有什么样的关系呢?
如上图所示:从上往下是三个大的层次:应用层、ART层(android run time)、Linux 层。每创建一个应用,都会经过如下步骤:
1、开启一个linux 进程
2、创建runtime 虚拟机
3、创建application 实例
4 创建启动这个应用的入口组件(如activity、service)
进程设置了优先级,这样os才能决定在资源不足时应该舍弃谁,android的优先级设定结合了android的基本组件
Foreground
application 有一个可见的组件在前台,有一个绑定到service的activity运行在前台的另一个进程中,有broadcast在运行
Visiable
application 有一个部分可见的组件
Service
service在后台运行,未绑定到前台activity中
Background
一个不可见的activity
Empty
没有活跃的组件
每一个应用外面都包裹着art虚拟机、Linux 进程,运行在Linux os中,进程设置了优先级,方便os对进程进行资源的调度和管理,为了提高用户体验,进程内部开辟了特殊的ui线程,也就是main线程来更新ui,其他耗时操作都应该重新开辟线程
线程都是从进程中创建的,而且,所有的线程都是linux thread。线程跟进程很想,唯一的差别就是能不能共享资源。linux os层面关心的更多的是线程,而不是进程,不管外在的应用有什么样的形式,在底层就是线程的执行,linux 依赖什么来调度线程呢,线程之间的竞争又是依靠什么,有两个因素:
priority
改变线程的优先级
control group
改变android指定的cgroup
priority:
基本上线程创建时,就会从创建它的线程集成它的优先级, 如下图所示。uithread创建的工作线程有着和自己一样的default优先级,反过来还会和自己竞争资源,我们一定要手动设定工作线程的优先级,一般是 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
Thread parent = currentThread();
if (g == null) {
g = parent.getThreadGroup();
}
g.addUnstarted();
this.group = g;
this.target = target;
this.priority = parent.getPriority();
this.daemon = parent.isDaemon();
setName(name);
init2(parent);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
tid = nextThreadID();
}
control group
cgroup | process rank |
fg | foreground |
fg | visibale |
bg | service |
bg | background |
bg | empty |
如果进程在前台,那么它创建的线程都属于fg,会获取更多执行时间,如果按home键,应用切换到后台,那么原来属于fg的线程会变成属于bg。另外,前面我们说的主动降低线程的优先级,也会将此线程放置到bg,尽管有时它创建于前台进程。
二、线程种类
1、handlerthread
最大特点就是执行任务的顺序性,另外就是handler的特点
容易使用和复用,sendmessage即可
任务容易组成任务链,通过handler的message.what串联起来
任务之间通过handler传递data方便
2、executor
最大特点就是复用线程,通过生产者消费者模型,并发执行多个任务,可以和service结合,能够被多个组件共享调用,生命周期也独立于调用组件,通过intent调用,可跨进程
内部执行:
1、如果线程个数小于核心,则开启线程执行
2、如果能够放进阻塞队列,则放入,否则,3
3、是否超过最大线程数,未超过,则创建,否则4
4、拒绝
3、intentservice
内部其实是个handlerthread,但是由于是service组件包装,所以提高了优先级,而且独立于启动它的组件的生命周期,handlerthread的适用场景同样也适用于intentservice,有一个特殊场景需要注意,broadcast 的onreceive执行在主线程,当有耗时操作时,需要开启线程,但是onreceive执行完,则broadcast组件生命周期结束,如果这是进程的入口,那么进程会变为一个空进程,很容易被杀死,这时候intentservice就是个很好的选择。
如果任务的执行受控制于客户侧,或者需要并发执行,则建议适用service 内部建立多线程调度的方式