- AsyncTask封装了线程池和Handler,它主要是为了方便开发者在子线程中更新UI。
- HandlerThread是一种具有消息循环的线程,在它的内部可以使用Handler。
- IntentService是一个服务,系统对其进行了封装使其可以更方便地执行后台任务,IntentService 内部采用HandlerThread来执行任务,当任务执行完毕后IntentService 会自动退出。 它不容易被系统杀死从而可以尽量保证任务的执行。
11.1 主线程和子线程
- 主线程:进程所拥有的线程,主要处理界面交互相关的逻辑。
- 子线程:除主线程之外都是子线程,主要用于执行耗时操作。
11.2 Android中的线程形态
11.2.1 AsyncTask
轻量级的异步任务类,可以执行后台任务以及在子线程中进行UI操作。
主要方法:
- onPreExecute()
- doInBackground(Params…params):
- onProgressUpdate(Progress…values)
- onPostExecute(Result result)
- onCancelled()
- execute(Params...params)
11.2.2 AsyncTask的工作原理
- AsyncTask构造方法中:
- 实例化Handler,类型是InternalHandler,用于切换到主线程
- 实例化mWorker,类型是WorkerRunnable,封装了Params和Result;
- 实例化mFuture,类型是FutureTask,参数为mWorker。FutureTask是一个并发类,在这里它充当了Runnable的作用。
- 执行任务
execute
方法会调用executeOnExecutor(sDefaultExecutor, params)
。- 参数sDefaultExecutor,类型为SerialExecutor,是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行。
- SerialExecutor#execute。(1) ArrayDeque.offer(Runnable)。把FutureTask对象插入到任务队列mTasks中;(2) scheduleNext()。如果没有正在活动的任务,或者当一个任务执行完后,会调用scheduleNext方法执行下一个任务,直到所有的任务都被执行。scheduleNext中,调用THREAD_POOL_EXECUTOR.execute(),真正地执行任务。
- executeOnExecutor
- 调用
onPreExecute()
- exec.execute(mFuture);线程池执行。
- 调用
- 响应结果
- mWorker的call()中调用
doInBackground(mParams)
和 postResult() - postResult中,Handler调用sendToTarget()发送消息。
- InternalHandler中,
onProgressUpdate
和finish。
- mWorker的call()中调用
结束或取消
onCancelled
、onPostExecute
从Android 3.0 开始,默认情况下AsyncTask是串行执行的,可以调用
executeOnExecutor
方法并行执行。
11.2.3 HandlerThread
- HandlerThread本质上是一个线程类,它继承了Thread;
- HandlerThread有自己的内部Looper对象,可以进行looper循环;
- 通过获取HandlerThread的looper对象传递给Handler对象,可以在handleMessage方法中执行异步任务。
- 创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run方法,创建Looper对象。
- 当不需要HandlerThread时,通过HandlerThread.quit()/quitSafely()方法来终止线程的执行
11.2.4 IntentService
可自动创建子线程来执行任务,且任务执行完毕后自动退出。
- 在IntentService.onCreate()里创建一个Handle对象即HandlerThread,利用其内部的Looper会实例化一个ServiceHandler对象;
- 任务请求的Intent会被封装到Message并通过ServiceHandler发送给Looper的MessageQueue,最终在HandlerThread中执行;
- 在ServiceHandler.handleMessage()中会调用IntentService.onHandleIntent(),可在该方法中处理后台任务的逻辑。
11.3 Android中的线程池
线程池的优点:
- 重用线程池中的线程,避免线程的创建和销毁带来的性能消耗;
- 有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致阻塞现象;
- 能够进行线程管理,提供定时/循环间隔执行等功能。
Android中的线程池的概念来源于Java中的Executor, Executor是一个接口,真正的线程池的实现为ThreadPoolExecutor。ThreadPoolExecutor 提供了一系列参数来配置线程池,通过不同的参数可以创建不同的线程池。
11.3.1 ThreadPoolExecutor
ThreadPoolExecutor构造方法:
public ThreadPoolExecutor(
int corePoolSize, //核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//非核心线程超时时间
TimeUnit unit,//keepAliveTime参数的时间单位
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory,//线程工厂,可创建新线程
RejectedExecutionHandler handler//饱和策略
)
ThreadPoolExecutor的默认工作策略:
- 如果线程池中的线程数量未达到核心线程数,则会直接启动一个核心线程执行任务。
- 若线程池中的线程数量已达到或者超过核心线程数量,则任务会被插入到任务列表等待执行。
- 若任务无法插入到任务列表中,往往由于任务列表已满,此时如果:
- 线程数量未达到线程池最大线程数,则会启动一个非核心线程执行任务;
- 线程数量已达到线程池规定的最大值,则拒绝执行此任务
如果条件为否:核心线程 > 任务列表 > 非核心线程 > 拒接任务。
AsyncTask的THREAD_POOL_EXECUTOR线程池配置参数:
- 核心线程数:CPU_COUNT - 1,最小为2最大为4;
- 线程池的最大线程数:CPU_COUNT * 2+ 1;
- 核心线程无超时机制,非核心线程在闲置时的超时时间为30秒;
- 任务队列的容量为128。
11.3.2 线程池的分类
- FixedThreadPool:
- 含义:线程数量固定的线程池,所有线程都是核心线程,当线程空闲时不会被回收。
- 特点:能快速响应外界请求。
- CachedThreadPool:
- 含义:线程数量不定的线程池(最大线程数为Integer.MAX_VALUE),只有非核心线程,空闲线程有超时机制,60s超时回收。
- 特点:适合于执行大量的耗时较少的任务
- ScheduledThreadPool:
- 含义:核心线程数量固定,非核心线程数量不定。
- 特点:定时任务和固定周期的任务。
- SingleThreadExecutor:
- 含义:只有一个核心线程,可确保所有的任务都在同一个线程中按顺序执行。
- 特点:无需处理线程同步问题。