简单介绍:
在操作系统中,线程是系统所能调用的最小单元,同时线程是一种受限的系统资源,因此不可能无限制的产生,并且线程的创建和销毁都会有相应的开销,试想一下,如果在一个进程中频繁的创建和销毁线程,势必会产生内存的抖动,显然这不是高效的做法,那么正确的做法就是采用线程池,通过线程池可以避免因为频繁创建和销毁带来的系统开销,android线程来源于java,因此主要也是通过Executor来派生特定类型的线程池。不同种类的线程池又具有各自的特性。
线程种类:
除了Thread之外,在android可以扮演线程角色的还有很对,例如AsyncTask,IntentService以及HandlerThread,HandlerThread是一种特殊的线程,虽然AsyncTask,IntentService以及HandlerThread有别于Thread,但是他们的本质仍然是线程。对于AsyncTask而言,它的底层用到了线程池,对于IntentService和HandlerThread,他们的底层直接使用了线程。
使用场景:
AsyncTask封装了线程池和handler,他主要方便开发者在子线程中更新UI。
HandlerThread是具有消息循环的线程,在它的内部可以使用handler
IntentService是一个服务,系统对它进行了封装,是它更方便处理后台任务,其实它的内部采用HandlerThread执行任务,当任务执行完成后IntentService会自动退出。从任务执行的角度看,IntentService很像一个后台线程,但他又是一个服务,由于service不容易被系统杀死从而可以尽量保证任务的执行。
AsyncTask:
AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI,从实现上来说,AsyncTask封装了Thread和Handler,通过它可以更加方便的执行后台任务并在主线程中更新ui,但是AsyncTask并不适合进行特病耗时的任务,对于特别耗时的任务的任务建议采用线程池。
AsyncTask是一个抽象的泛型类,它提供了Params,Progress,Result等三个泛型参数,其中params表示参数的类型,progress表示后台任务执行的进度,而Result表示后台任务执行完成返回结果的类型,如果不传递参数,那么这个三个泛型可以使用Void来代替,下面看下AsyncTask的声明:
public abstract class AsyncTask<Params, Progress, Result>
AsyncTask有四个核心方法,他们的含义如下所示:
onPreExecute() : 当主线程执行异步方法之前调用,用于准备工作,例如显示加载对话框
doInBackground(Param... params) : 此方法在线程池中执行,此方法用于异步任务的执行,其中Params代码参数类型,Params... 表示参数是可变长度,其实就相当于数组,此方法的参数类型就是execute(Param... params)传入的,此方法通过调用publishProgress更新任务的进度,同时publishProgress会调用onProgressUpdate()方法。此方法返回的结果将作为onPostExecute()的参数。
onProgressUpdate(Progress... values) :更新任务执行的进度
onPostExecute(Result result):在主线程中执行,在异步执行完成之后,此方法会被调用,其中Result参数是后台任务返回的结果,即doInBackground的返回值。
这几个方法的执行顺序是:首先执行onPreExecute(),然后doInBackground在后台执行,执行的过程中通过onProgressUpdate更新执行任务的进度,最后任务执行完毕回调onPostExecute(),当然,除了以上四个方法之外,还有一个onCancelled()方法,此方法在异步取消时被调用,这个时候onPostExecute就不会被调用。
下面我们实例化一个AsyncTask的实例:
public void test(){
String url = "wwww.baidu.com";
AsyncTask asyncTask = new DownloaderAsyncTask();
asyncTask.execute(url);
}
class DownloaderAsyncTask extends AsyncTask<String,Integer,String>{
@Override
protected String doInBackground(String... params) {
return null;//后台任务执行
}
@Override
protected void onPreExecute() {
super.onPreExecute();//准备工作,如显示加载提示框
}
@Override
protected void onProgressUpdate(Integer[] values) {
super.onProgressUpdate(values);//后台任务进度更新
}
@Override
protected void onPostExecute(String o) {
super.onPostExecute(o);//后台执行完成执行,并将结果作为参数返回,如果后台任务取消就会回调onCancelled(),此方法不回调。
}
}
AsyncTask在具体的过程中也有一些限制的,主要有一下几点:
1、AsyncTask 类补习在主线程中加载
2、AsyncTask的对象必须在主线程中创建
3、execute方法必须在UI线程调用
4、不要在程序中调用onPreExecute(),doInBackground(),onProgressUpdate,onPostExecute方法
5、AsyncTask对象只能执行一次,
6、在Android 1.6之前,AsyncTask是串行执行任务的,Android1.6的时候采用线程池处理并行任务,但是Android3.0为了避免AsyncTask并发的错误,AsyncTask又采用一个线程串行执行任务,尽管如此,3.0以后我们可以调用executeOnExecutor()方法来并行执行任务。
AsyncTask的工作原理:
为了分析AsyncTask的工作原理,我们从execute方法开始分析,execute方法又调用executorOnExecutor()方法,他们的实现如下所示:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
上面的代码中,sDefaultExecutor实际是一个串行的线程池,一个进程中所有的AsyncTask全部在这个串行的线程池中排队执行,在executeOnExecutor方法中,Asynctask的onPreExecute方法最先执行,然后线程池开始执行,下面分析线程池的执行的过程,如下所示:
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor{
final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();
Runnable mActive;
@Override
public void execute(@NonNull final Runnable command) {
mTasks .offer(new Runnable() {
@Override
public void run() {
command.run();
scheduleNext();
}
});
if(mActive != null){
scheduleNext();
}
}
private void scheduleNext() {
if((mActive = mTasks.poll()) != null){
THREAD_PO0L_EXECUTOR.executor(mActive);
}
}
}
从SerialExecutor的实现可以分析AsyncTask的排队执行的过程,首先系统会把AsyncTask的Params的参数封装成FutureTask对象,FutureTask是一个并发类,在这里充当了Runnable的作用,接着FutureTask会交给SerialExecutor的execute方法去处理,SerialExecutor的execute方法会把FutureTask对象插入到任务栈mTasks中,如果这个时候没有正在活动的AsyncTask任务,那么就会调用scheduleNext执行了下一个任务直到最后一个任务都被执行完成为止,从这点可以看出Asynctask是串行执行。
AsyncTask有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正执行任务,InternalHandler用于将执行环境从线程池切换到主线程,在AsyncTask的构造方法有如下代码,由于FutureTask的run方法会调用mWorker的call方法,因此mWorker的call方法最终会在线程池中执行:
mWorkerRunnable = new WorkRunnable<Params,Result>(){
public Result Call() throws Exception{
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return postResult(doInBackground(Params));
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
private static class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
finish方法中的逻辑也比较简单,如果AsyncTask被取消执行了,那么就调用onCancelled(),否则调用onPostExecute(),可以看到doInBackground的返回结果传递给onPostExecute方法。
HandlerThread:
HandlerThread继承了Thread,他是一种可以使用Handler的Thread,它的实现也很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,HandlerThread的run方法如下所示:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
它和普通Thread的不同,普通Thread主要用于在run方法中执行一个耗时任务,而HandlerThread在内部创建一个消息队列,外界需要通过Handler消息方式通知HandlerThread执行一个具体的任务,由于HandlerThread的run方法是一个无限循环,因此当明确不需要使用HandlerThread时,可以通过quit或者quitSafely方法来终止线程执行,这是一个良好的编程习惯。
IntentService:
IntentService是一个特殊的Service,他继承了Service并且是一个抽象类,因此必须创建子类才能使用IntentService,IntentService可用于执行后台耗时任务,当任务执行后它会自动停止,IntentService因为是Service,所以优先级比较高,不容易被后台杀死,实际上,IntentService封装了HandlerThread和Handler,这一点可以在onCreate方法中看出:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
当IntentService被第一次启动时,它的onCreate()方法会被调用,onCreate()方法会创建一个HandlerThread,然后使用Looper创建一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终会在HandlerThread中执行,IntentService执行后台任务,每次启动都会调用onStartCommand(),然后在onstartCommand()中调用onStart(),onstart()如下所示:
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
onlHandleIntent方法是一个抽象方法,他需要我们在子类中实现,它的作用是从Intent参数中区分具体的任务并执行这些任务,那么在onHandlerIntent方法执行完成这个任务后,stopSelf(int startId)就会直接停止服务,如果目前存在多个后台任务,那么当onHandIntent方法执行最后一个任务时,stopSelf(int stratId)才会直接停止服务,