第十一章 Android的线程和线程池

AsyncTask

  1. 三个参数(都可为Void):
    Params:参数
    Progress:执行进度
    Result:返回值
  2. 四个方法 :
    onPreExecute() 主线程执行,异步方法执行前调用。
    doInBackground(Params...params) 线程池中执行,用于执行异步任务;在方法内部用publishProgress 来更新任务进度。
    onProgressUpdate(Progress...value)主线程执行,后台任务进度状态改变时被调用。
    onPostExecute(Result result) 主线程执行,异步任务执行之后被调用
    执行顺序: onPreExecute->doInBackground->onPostExecute 如果取消了异步任务,会回调onCancelled(),onPostExecute则不会被调用

Tips: AsyncTask的类必须在主线程加载,Android4.1及以上已经被系统自动完成了;AsyncTask对象必须在主线程创建;execute方法需要在UI线程调用;一个AsyncTask对象只能调用一次;Android1.6之前串行执行,Android1.6采用线程池并行处理任务,Android3.0开始,采用一个线程执行任务,但也可以通过executeOnExecutor方法来并行执行任务




AsyncTask的工作原理

  • AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个InternalHandler,其中线程池SerialExecutor用于任务排队,THREAD_POOL_EXECUTOR用于真正执行任务,InternalHandler用于将执行环境切换到主线程

  • AsyncTask的排队过程:系统首先会把AsyncTask的Params参数封装成FutureTask对象,它充当Runnable的作用,接下来这个FutureTask会交给SerialExecutor的execute方法处理,execute方法首先会把FutereTask对象插入到任务队列mTasks中去;如果没有正在活动的AsyncTask任务,就会执行下一个AsyncTask任务;同时当一个AsyncTask任务执行完成后,AsyncTask会继续执行其他任务直到所有任务都执行为止,可以看出默认情况,AsyncTask是串行执行的(Android3.0后)

  • 先看一段示例:

        

    1. package com.example.zhy_asynctask_demo01;
    2. import android.app.Activity;
    3. import android.app.ProgressDialog;
    4. import android.os.AsyncTask;
    5. import android.os.Bundle;
    6. import android.util.Log;
    7. import android.widget.TextView;
    8. public class MainActivity extends Activity
    9. {
    10. private static final String TAG = "MainActivity";
    11. private ProgressDialog mDialog;
    12. private TextView mTextView;
    13. @Override
    14. protected void onCreate(Bundle savedInstanceState)
    15. {
    16. super.onCreate(savedInstanceState);
    17. setContentView(R.layout.activity_main);
    18. mTextView = (TextView) findViewById(R.id.id_tv);
    19. mDialog = new ProgressDialog(this);
    20. mDialog.setMax(100);
    21. mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    22. mDialog.setCancelable(false);
    23. new MyAsyncTask().execute();
    24. }
    25. private class MyAsyncTask extends AsyncTask<Void, Integer, Void>
    26. {
    27. @Override
    28. protected void onPreExecute()
    29. {
    30. mDialog.show();
    31. Log.e(TAG, Thread.currentThread().getName() + " onPreExecute ");
    32. }
    33. @Override
    34. protected Void doInBackground(Void... params)
    35. {
    36. // 模拟数据的加载,耗时的任务
    37. for (int i = 0; i < 100; i++)
    38. {
    39. try
    40. {
    41. Thread.sleep(80);
    42. } catch (InterruptedException e)
    43. {
    44. e.printStackTrace();
    45. }
    46. publishProgress(i);
    47. }
    48. Log.e(TAG, Thread.currentThread().getName() + " doInBackground ");
    49. return null;
    50. }
    51. @Override
    52. protected void onProgressUpdate(Integer... values)
    53. {
    54. mDialog.setProgress(values[0]);
    55. Log.e(TAG, Thread.currentThread().getName() + " onProgressUpdate ");
    56. }
    57. @Override
    58. protected void onPostExecute(Void result)
    59. {
    60. // 进行数据加载完成后的UI操作
    61. mDialog.dismiss();
    62. mTextView.setText("LOAD DATA SUCCESS ");
    63. Log.e(TAG, Thread.currentThread().getName() + " onPostExecute ");
    64. }
    65. }
    66. }

    进入某个Activity,Activity中需要的数据来自于网络或者其它耗时操作,可以在AsyncTask中onPreExecute完成一些准备操作,比如上例中显示进度对话框;然后在doInBackground完成耗时操作,在进行耗时操作时还能不时的通过publishProgress给onProgressUpdate中传递参数,然后在onProgressUpdate中可以进行UI操作,比如上例更新进度条的进度;当耗时任务执行完成后,最后在onPostExecute进行设置控件数据更新UI等操作,例如隐藏进度对话框。



    源码解析

    注:本篇源码分析基于Andorid-17,因为和3.0之前版本变动较大,有必要标出。

    那么大家一定好奇,AsyncTask在Android中是如何实现的,下面进行源码分析:从我们的执行异步任务的起点开始,进入execute方法:

    1. public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    2. return executeOnExecutor(sDefaultExecutor, params);
    3. }
    4. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
    5. Params... params) {
    6. if (mStatus != Status.PENDING) {
    7. switch (mStatus) {
    8. case RUNNING:
    9. throw new IllegalStateException("Cannot execute task:"
    10. + " the task is already running.");
    11. case FINISHED:
    12. throw new IllegalStateException("Cannot execute task:"
    13. + " the task has already been executed "
    14. + "(a task can be executed only once)");
    15. }
    16. }
    17. mStatus = Status.RUNNING;
    18. onPreExecute();
    19. mWorker.mParams = params;
    20. exec.execute(mFuture);
    21. return this;
    22. }

    18行:设置当前AsyncTask的状态为RUNNING,上面的switch也可以看出,每个异步任务在完成前只能执行一次。
    20行:执行了onPreExecute(),当前依然在UI线程,所以我们可以在其中做一些准备工作。
    22行:将我们传入的参数赋值给了mWorker.mParams
    23行:exec.execute(mFuture)

    相信大家对22行出现的mWorker,以及23行出现的mFuture都会有些困惑。
    mWorker找到这个类:

    1. private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
    2. Params[] mParams;
    3. }
    可以看到是Callable的子类,且包含一个mParams用于保存我们传入的参数,下面看初始化mWorker的代码:
    1. public AsyncTask() {
    2. mWorker = new WorkerRunnable<Params, Result>() {
    3. public Result call() throws Exception {
    4. mTaskInvoked.set(true);
    5. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    6. //noinspection unchecked
    7. return postResult(doInBackground(mParams));
    8. }
    9. };
    10. //….
    11. }
    可以看到mWorker在构造方法中完成了初始化,并且因为是一个抽象类,在这里new了一个实现类,实现了call方法,call方法中设置mTaskInvoked=true,且最终调用doInBackground(mParams)方法,并返回Result值作为参数给postResult方法.可以看到我们的doInBackground出现了,下面继续看:
    1. private Result postResult(Result result) {
    2. @SuppressWarnings("unchecked")
    3. Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
    4. new AsyncTaskResult<Result>(this, result));
    5. message.sendToTarget();
    6. return result;
    7. }
    可以看到postResult中出现了我们熟悉的异步消息机制,传递了一个消息message, message.what为MESSAGE_POST_RESULT;
    message.object= new AsyncTaskResult(this,result);
    1. private static class AsyncTaskResult<Data> {
    2. final AsyncTask mTask;
    3. final Data[] mData;
    4. AsyncTaskResult(AsyncTask task, Data... data) {
    5. mTask = task;
    6. mData = data;
    7. }
    8. }
    AsyncTaskResult就是一个简单的携带参数的对象。

    看到这,我相信大家肯定会想到,在某处肯定存在一个sHandler,且复写了其handleMessage方法等待消息的传入,以及消息的处理。


    1. private static final InternalHandler sHandler = new InternalHandler();
    2. private static class InternalHandler extends Handler {
    3. @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    4. @Override
    5. public void handleMessage(Message msg) {
    6. AsyncTaskResult result = (AsyncTaskResult) msg.obj;
    7. switch (msg.what) {
    8. case MESSAGE_POST_RESULT:
    9. // There is only one result
    10. result.mTask.finish(result.mData[0]);
    11. break;
    12. case MESSAGE_POST_PROGRESS:
    13. result.mTask.onProgressUpdate(result.mData);
    14. break;
    15. }
    16. }
    17. }
    哈哈,出现了我们的handleMessage,可以看到,在接收到MESSAGE_POST_RESULT消息时,执行了result.mTask.finish(result.mData[0]);其实就是我们的AsyncTask.this.finish(result),于是看finish方法
    1. private void finish(Result result) {
    2. if (isCancelled()) {
    3. onCancelled(result);
    4. } else {
    5. onPostExecute(result);
    6. }
    7. mStatus = Status.FINISHED;
    8. }
    可以看到,如果我们调用了cancel()则执行onCancelled回调;正常执行的情况下调用我们的onPostExecute(result);主要这里的调用是在handler的handleMessage中,所以是在UI线程中。

    最后将状态置为FINISHED。

    mWoker看完了,应该到我们的mFuture了,依然实在构造方法中完成mFuture的初始化,将mWorker作为参数,复写了其done方法。

    1. public AsyncTask() {
    2. ...
    3. mFuture = new FutureTask<Result>(mWorker) {
    4. @Override
    5. protected void done() {
    6. try {
    7. postResultIfNotInvoked(get());
    8. } catch (InterruptedException e) {
    9. android.util.Log.w(LOG_TAG, e);
    10. } catch (ExecutionException e) {
    11. throw new RuntimeException("An error occured while executing doInBackground()",
    12. e.getCause());
    13. } catch (CancellationException e) {
    14. postResultIfNotInvoked(null);
    15. }
    16. }
    17. };
    18. }
    任务执行结束会调用:postResultIfNotInvoked(get());get()表示获取mWorker的call的返回值,即Result.然后看postResultIfNotInvoked方法

    1. private void postResultIfNotInvoked(Result result) {
    2. final boolean wasTaskInvoked = mTaskInvoked.get();
    3. if (!wasTaskInvoked) {
    4. postResult(result);
    5. }
    6. }
    如果mTaskInvoked不为true,则执行postResult;但是在mWorker初始化时就已经将mTaskInvoked为true,所以一般这个postResult执行不到。
    好了,到了这里,已经介绍完了execute方法中出现了mWorker和mFurture,不过这里一直是初始化这两个对象的代码,并没有真正的执行。下面我们看真正调用执行的地方。
    execute方法中的:
    还记得上面的execute中的23行:exec.execute(mFuture)

    exec为executeOnExecutor(sDefaultExecutor, params)中的sDefaultExecutor

    下面看这个sDefaultExecutor
    1. private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    2. public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    3. private static class SerialExecutor implements Executor {
    4. final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    5. Runnable mActive;
    6. public synchronized void execute(final Runnable r) {
    7. mTasks.offer(new Runnable() {
    8. public void run() {
    9. try {
    10. r.run();
    11. } finally {
    12. scheduleNext();
    13. }
    14. }
    15. });
    16. if (mActive == null) {
    17. scheduleNext();
    18. }
    19. }
    20. protected synchronized void scheduleNext() {
    21. if ((mActive = mTasks.poll()) != null) {
    22. THREAD_POOL_EXECUTOR.execute(mActive);
    23. }
    24. }
    25. }

    可以看到sDefaultExecutor其实为SerialExecutor的一个实例,其内部维持一个任务队列;直接看其execute(Runnable runnable)方法,将runnable放入mTasks队尾;
    16-17行:判断当前mActive是否为空,为空则调用scheduleNext方法
    20行:scheduleNext,则直接取出任务队列中的队首任务,如果不为null则传入THREAD_POOL_EXECUTOR进行执行。
    下面看THREAD_POOL_EXECUTOR为何方神圣:
    1. public static final Executor THREAD_POOL_EXECUTOR
    2. =new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
    3. TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    可以看到就是一个自己设置参数的线程池,参数为:
    1. //现在已经根据CPU内核数目来设置线程池的大小了.

    1. private static final int CORE_POOL_SIZE = 5;
    2. private static final int MAXIMUM_POOL_SIZE = 128;
    3. private static final int KEEP_ALIVE = 1;
    4. private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    5. private final AtomicInteger mCount = new AtomicInteger(1);
    6. public Thread newThread(Runnable r) {
    7. return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    8. }
    9. };
    10. private static final BlockingQueue<Runnable> sPoolWorkQueue =
    11. new LinkedBlockingQueue<Runnable>(10);
    可以看到,如果此时有10个任务同时调用execute(s synchronized)方法,第一个任务入队,然后在mActive = mTasks.poll()) != null被取出,并且赋值给mActivte,然后交给线程池去执行。然后第二个任务入队,但是此时mActive并不为null,并不会执行scheduleNext();所以如果第一个任务比较慢,10个任务都会进入队列等待;真正执行下一个任务的时机是,线程池执行完成第一个任务以后,调用Runnable中的finally代码块中的scheduleNext,所以虽然内部有一个线程池,其实调用的过程还是线性的。一个接着一个的执行,相当于单线程。



     HandlerThread

    • HandlerThread继承了Thread,是一种可以使用Handler的Thread;在run方法中通过looper.prepare()来开启消息循环,这样就可以在HandlerThread中创建Handler了;外界可以通过一个Handler的消息方式来通知HandlerThread来执行具体任务;确定不使用之后,可以通过quit或quitSafely方法来终止线程执行;具体使用场景是IntentService。

    2.4 IntentService

    1. IntentSercie是一种特殊的Service,继承了Service并且是抽象类,任务执行完成后会自动停止,优先级远高于普通线程,适合执行一些高优先级的后台任务;
    2. IntentService封装了HandlerThread和Handler,onCreate方法自动创建一个HandlerThread,然后用它的Looper构造了一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息都会在HandlerThread执行;
      IntentServiced的onHandlerIntent方法是一个抽象方法,需要在子类实现,onHandlerIntent方法执行后,stopSelt(int startId)就会停止服务,如果存在多个后台任务,执行完最后一个stopSelf(int startId)才会停止服务

















    原文地址:https://www.cnblogs.com/You0/p/5984482.html