一、线程
在Android系统中,线程分为主线程与子线程,众所周知,主线程主要处理和UI相关的操作,而子线程则用于处理耗时的操作,除了Thread外,扮演线程角色的还有AsyncTask、IntentService和HandlerThread等。AsyncTask封装了线程池和Handler,主要是为了方便开发者在子线程中更新UI;HandlerThread是一个消息循环的线程,其内部可以使用Handler;IntentService是一个服务,系统对其封装后使其更加方面的执行后台操作,使用了HandlerThread来执行任务。
1、AsyncTask
AsyncTask是一个轻量的异步任务类,它主要是在线程池中执行后台任务,然后把执行的进度和结果传递给主线程中并更新UI,由于AsyncTask的设计初衷是为了执行简单的后台任务,并在主线程中快速更新UI和默认的串行执行方式(在Android1.6前是串行执行,在Android1.6改为并行执行,但是为了避免并行执行带来的错误,在Android3.0时又将AsyncTask改回串行执行,但是提供了executeOnExecutor方法执行并行任务)使得AsyncTask并不适合执行耗时的操作。
AsyncTask是一个抽象的泛型类,有params、progress和result三个参数,分别表示参数的类型、后台任务的执行进度的类型、后台任务返回结果的类型。主要的方法有四个:onPreExecute、onPostExecute、onProgressUpdate和doInBackground。
private class DownloadAsyncTask extends AsyncTask<Void, Void, Void >{
@Override
protected void onPreExecute() { //准备工作
super.onPreExecute();
}
@Override
protected void onPostExecute(Void aVoid) { //任务完成后执行的方法(在主线程中)
super.onPostExecute(aVoid);
}
@Override
protected void onProgressUpdate(Void... values) { //任务执行中,更新进度的方法(在主线程中)
super.onProgressUpdate(values);
}
@Override
protected Void doInBackground(Void... voids) { //在后台执行任务的方法(在子线程中)
return null;
}
}
DownloadAsyncTask downloadAsyncTask = new DownloadAsyncTask(); //在主线程中创建
downloadAsyncTask.execute();//串行执行
downloadAsyncTask.executeOnExecutor(executor); //并行执行
在AsyncTask的使用过程有如下注意事项:
1、AsyncTask的对象必须在主线程中创建
2、execute方法必须在UI线程中调用
3、不能直接调用onPreExecute、onPostExecute、onProgressUpdate和doInBackground等方法。
4、一个AsyncTask对象只能调用一次execute方法。
2、HandlerThread
HandlerThread继承了Thread,是一种可以使用Handler的Thread,在run方法中通过looper.prepare()方法创建了消息队列,并通过Looper.loop()开启了消息循环,因此可以创建一个Handler,并通过Handler的消息方式来通知HandlerThread执行一个具体的任务。
3、IntentService
IntentService是一种特殊的Service,继承了Service并且是它的一个抽象类,因此必须创建它的子类才能使用IntentService。IntentService封装了HandlerThread和Handler,当第一次启动时,onCreate方法会被调用,并创建一个HandlerThread,然后它的looper构建了一个Handler对象mServiceHandler。随后每次启动,IntentService方法就会被调用。IntentService的创建:
private class IntentService extends android.app.IntentService{
public IntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
}
}
IntentService与Service的区别:
1、service与应用程序在同一个进程中,同时没有创建新线程的操作,如果执行耗时任务,仍需手动创建新线程
2、IntentService使用队列的方式将请求的Intent加入队列,然后开启了一个Worker Thread(工作线程)在处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后在处理第二个,每一个请求都会在一个单独的Worker Thread中处理,不会阻塞应用程序的主线程。
二、线程池
线程池优点:
1、重用线程池中的线程,避免因线程的创建和销毁所带来的性能开销
2、能有效控制线程池的最大并发数,避免大量线程之间因相互抢占系统资源而导致的阻塞现象。
3、能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。
1、ThreadPoolExecutor
由于Android线程池都是直接或者间接通过配置ThreadPoolExecutor来实现,因此简单介绍一下ThreadPoolExecutor。在ThreadPoolExecutor的构造方法中有如下参数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
①corePoolSize
线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使处于闲置状态。如果设置allowCoreThreadTimeOut为true,那么闲置的核心线程就有一个超时策咯,该超时由keepAliveTime所指定,超时后,该核心线程会被终止。
②maximumPoolSize:线程池能容纳的最大线程数,当活动线程数超过该值,后续线程会被阻塞
③keepAliveTime:非核心线程闲置的超时时长
④unit:指定keepAliveTime的时间单位
⑤workQueue:线程池中的任务队列
⑥threadFactory:线程工厂,为线程池提供创建新线程的功能
2、线程池分类
1、FixedThreadPool
一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。只有核心线程,且核心线程不会被回收,因此能哈快速相应外界请求。没有超时机制、任务队列没有大小限制。
2、CachedThreadPool
线程数量不定、只有非核心线程,最大线程数为Integer.Max_VALUE,消息队列是一个空集合,导致任何任务都可以立即被执行。综上,该线程池比较适合执行大量的耗时少的任务。
3、ScheduledThreadPool
核心线程数量是固定的,非核心线程数量是没有限制的,当非核心线程闲置时会被立即回收,主要用于执行定时任务和具有固定周期的重复任务。
4、SingleThreadExecutor
只有一个核心线程,所有任务都在同一个线程中按顺序执行,不需要处理线程同步的问题。
部分内容参考自:《Android开发艺术探索》