1. 程式人生 > >Android多執行緒(二)AsyncTask原始碼分析

Android多執行緒(二)AsyncTask原始碼分析

AsyncTask的基本用法這裡就不在贅述了,是個安卓開發者就會。

1.android 3.0以前的 AsyncTask

private static final int CORE_POOL_SIZE = 5;  
private static final int MAXIMUM_POOL_SIZE = 128;  
private static final it KEEP_ALIVE = 10;  
……  
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,  
        MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);  

在這裡同一時刻能夠執行的執行緒數為5個,執行緒池總大小為128,當執行緒數大於核心時,終止前多餘的空閒執行緒等待新任務的最長時間為10秒。在3.0之前的AsyncTask可以同時有5個任務在執行,而3.0之後的AsyncTask同時只能有1個任務在執行。

2.讓我們來看看android 4.3版本的 AsyncTask

AsyncTask建構函式:

 /**
     * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
     */
    public AsyncTask() {
        mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
        };

        mFuture = new FutureTask<Result>(mWorker) {
            @Override
            protected void done() {
                try {
                    postResultIfNotInvoked(get());
                } catch (InterruptedException e) {
                    android.util.Log.w(LOG_TAG, e);
                } catch (ExecutionException e) {
                    throw new RuntimeException("An error occured while executing doInBackground()",
                            e.getCause());
                } catch (CancellationException e) {
                    postResultIfNotInvoked(null);
                }
            }
        };
    }

這段程式碼初始化了兩個變數,mWorker和mFuture,並在初始化mFuture的時候將mWorker作為引數傳入。mWorker是一個Callable物件,mFuture是一個FutureTask物件,這兩個變數會暫時儲存在記憶體中,稍後才會用到它們。

我們要運用AsyncTask時,大多時候會呼叫execute()方法,來看看execute()的原始碼:

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);}

返回了executeOnExecutor並傳進去sDefaultExecutor(預設的執行緒池)。先看看executeOnExecutor的原始碼:

 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;
    }

傳入的執行緒池exec呼叫了execute方法並將上文提到的mFuture傳了進去。

這個傳進來的執行緒池sDefaultExecutor就是預設的執行緒池SerialExecutor也就是呼叫了SerialExecutor的execute()方法:

  public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
  private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

SerialExecutor的原始碼:

        private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

呼叫SerialExecutor的execute方法這裡可以看到傳進來一個Runnable,這個Runnable就是上文提到的mFuture(FutureTask),第九行執行了FutureTask的run方法:

 public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

在run方法中執行了c.call,這裡的c就是我們上文提到的mWorker(WorkerRunnable)。執行WorkerRunnable的call方法:

 mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);

                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }


最後一行postResult()方法原始碼:

 private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

我們發現就是傳送了一個訊息,上面的程式碼傳送的訊息由這裡接受:

private static class InternalHandler extends Handler {
        @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;
            }
        }
    }


訊息是MESSAGE_POST_RESULT所以會執行 result.mTask.finish(result.mData[0])  ,finish原始碼:

  private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

當被取消時會執行 onCancelled(result);否則就會呼叫 onPostExecute(result);這樣我們就可以在onPostExecute方發中得到我們需要的結果result來進行下一步的處理了。

3.AsyncTask中的執行緒池        AsyncTask中一共定義了兩個執行緒池一個是此前我們已經介紹了執行緒池SerialExecutor,這個是目前我們呼叫AsyncTask.execute()方法預設使用的執行緒池,這個在前一篇文章中已經講到過了,另一個是3.0版本之前的預設執行緒池THREAD_POOL_EXECUTOR。現在我們來回顧一下SerialExecutor的原始碼:
private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }
這個預設的執行緒池同一時間只能處理一個任務,一個任務完成以後才可以執行下一個任務,相當於Executors.newSingleThreadPool()。上面的arrayDeque是一個裝載Runnable的佇列,如果我們一次性啟動了很多個任務,在第一次執行execute()方法的時候會呼叫ArrayDeque的offer()方法將傳入的Runnable物件新增到佇列的尾部, 然後判斷mActive物件是不是等於null,第一次執行等於null,於是呼叫scheduleNext()方法。另外在finally中也呼叫了scheduleNext()方法,這樣保證每次當一個任務執行完畢後,下一個任務才會執行。我們來看看scheduleNext()方法的原始碼:
  protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }

首先從runnable佇列的頭部取值,如果不為空就賦值給mActive物件,然後呼叫THREAD_POOL_EXECUTOR去執行取出的Runnable物件。THREAD_POOL_EXECUTOR原始碼:
  private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;
...
  public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
這是3.0版本之前的執行緒池,同一時刻能夠執行的執行緒數為5個,workQueue總大小為128。當我們啟動10個任務,只有5個任務能夠優先執行,其餘的任務放在workQueue中,當workQueue大於128時就會呼叫RejectedExecutionHandler來做拒絕處理。當然在3.0之前是並沒有SerialExecutor這個類的。如果不希望用預設執行緒池我們也可以使用這個3.0版本之前的執行緒池
AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);
同時3.0版本也提供了executeOnExecutor這個方法可以傳入AsyncTask定義的執行緒池也可以傳入Executor定義的4種執行緒池,不知道這四種執行緒池的可以看http://blog.csdn.net/itachi85/article/details/44874511 傳入CachedThreadPool:
                LikeListTask mLikeListTask=new LikeListTask();
		mLikeListTask.executeOnExecutor(Executors.newCachedThreadPool(), null);
當然我們也可以傳入自定義的執行緒池:
Executor exec =new ThreadPoolExecutor(0,  Integer.MAX_VALUE,     
				  0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());    
		new LikeListTask().executeOnExecutor(exec, null);
我們看到這裡定義的是一個類似於CachedThreadPool的一個執行緒池
          

相關推薦

Android執行()AsyncTask原始碼分析

AsyncTask的基本用法這裡就不在贅述了,是個安卓開發者就會。 1.android 3.0以前的 AsyncTask private static final int CORE_POOL_SIZE = 5; private static final int MAX

Android執行AsyncTask

  對Android開發者來說,如何處理多執行緒問題是無法繞過的問題。每個Android開發者或多或少都遇到過ANR(Applicatin Not Responding)異常,Android預設當UI執行緒阻塞超過20s時將會引發ANR異常。因此在處理耗時操

Java執行 -- JUC包原始碼分析18 -- ConcurrentSkipListMap(Set)/TreeMap(Set)/無鎖鏈表

-為什麼是SkipList,不是TreeMap的紅黑樹? -無鎖鏈表的精髓 -ConcurrentSkipListMap -ConcurrentSkipListSet 為什麼是SkipList? 大家都知道,在Java集合類中,有一個TreeMap

Android執行---AsyncTask原始碼分析

Android多執行緒—AsyncTask使用原始碼分析 一、前言 上篇文章對 HandlerThread 的原始碼進行了分析,相信大家對 HandlerThread 有了一定的認識。如果我們需要執行一個非同步任務,並且執行完畢之後在主執行緒中更新

我的android執行程式設計之路(2)之RxJava Schedulers原始碼分析

寫在伊始 上一篇介紹了執行緒的一些基礎知識和工作這麼久以後對於多執行緒部分的使用經驗之路,這篇主要對RxJava執行緒控制部分進行分析。 RxJava(本文就RxJava2.0分析) 說實話,近一年多一直在用rxjava進行專案架構的編寫及封裝及一些非

我的android執行程式設計之路(1)之經驗詳解,原始碼分析

寫在伊始 android開發這麼久了,對於多執行緒這塊一直處於似懂非懂的神奇狀態,今天總結出來,分享一下,希望大家多多指正。共同交流,懇望得到您的建議。 本文簡介 本文會基於自己在開發中對於執行緒這塊的實際使用,大概從執行緒程序的概念,執行緒的建立(T

Android執行-AsyncTask工作流程(原始碼)

AsyncTask的原始碼是很簡單的,看著並不複雜。只是對Handler和ThreadPoolExecutor進行了一下封裝。 基於api25(7.1)的程式碼, 使用起來也是很簡單的,看上個就知道了。一般要繼承AsyncTask並重寫下面幾個方法,這些方法

Android執行之(一)View.post()原始碼分析——在子執行中更新UI

       提起View.post(),相信不少童鞋一點都不陌生,它用得最多的有兩個功能,使用簡便而且實用:        1)在子執行緒中更新UI。從子執行緒中切換到主執行緒更新UI,不需要額外new一個Handler例項來實

Android執行分析之一:使用Thread非同步下載影象

Android多執行緒分析之一:使用Thread非同步下載影象 羅朝輝 (http://blog.csdn.net/kesalin) CC 許可,轉載請註明出處 打算整理一下對 Android Framework 中多執行緒相關知識的理解,主要集中在 Fra

Android執行

  在上一篇中,我簡單說了用AsyncTask來完成簡單非同步任務,但AsyncTask是把所有的非同步任務放到一個佇列中依次在同一個執行緒中執行。這樣就帶來一個問題,它無法處理那些耗時長、需要並行的的任務。如何處理這個難題呢?一是自己開啟執行緒然後處理執行緒通訊問題,二是使用HandlerThre

python執行探討 基於原始碼 初步分析

這篇文章 應該有人需要 因為我現在都需要 所以標了個關鍵字初步 摘自百度百科 儘管提高CPU的時鐘頻率和增加快取容量後的確可以改善效能,但這樣的CPU效能提高在技術上存在較大的難度。實際上在應用中基於很多原因,CPU的執行單元都沒有被充分使用。如果CPU不能正常讀取資料(

Android執行-----非同步(AsyncTask

一、總述 在Android當中,提供了非同步訊息處理機制的兩種方式來解決執行緒之間的通訊問題,一種是通過Handler的機制(這種方式在後面的部落格中將詳細介紹),還有一種就是今天要詳細講解的 AsyncTask 機制。 Android中的工作者執行緒主要有AsyncTask、In

Android執行-AsyncTask的使用和問題(取消,並行和序列,螢幕切換)

AsyncTask是Android提供的一個執行非同步工作的類,內部其實是運用了執行緒池和Handler來進行非同步任務的執行和與主執行緒的互動。AsyncTask只是一個輔助類,適合執行時間短的非同步任務。 本文基於Android7.0的程式碼來說的。

Android執行任務優化1:探討AsyncTask的缺陷

導語:在開發Android應用的過程中,我們需要時刻注意保障應用的穩定性和介面響應性,因為不穩定或者響應速度慢的應用將會給使用者帶來非常差的互動體驗。在越來越講究使用者體驗的大環境下,使用者也許會因為應用的一次Force Close(簡稱FC)或者延遲嚴重的動畫效果而解除安

HashMap原始碼執行併發問題深度分析

以前只知道HashMap是執行緒不安全的,拿來就用,也不會考慮會出現什麼後果,直到最近在學習中終於暴露出了HashMap的短板出來,可又百思不得其解,於是在網上拜讀了若干大牛有關HashMap的分析文章,發現他們其實寫於很早之前,而HashMap的原始碼都已

Android執行理解

Android 理解多執行緒 安卓應用程式通常是應用在一個單獨的執行緒裡的,即為主執行緒,用於顯示使用者介面以及響應使用者的操作。 如果一些耗時任務也同時在主執行緒裡去完成,則會影響使用者體驗,會阻塞UI主執行緒。我們會建立一個單獨的執行緒或者子執行緒,去處理這些耗時操作(如網路請求、

android執行斷點下載

多執行緒斷電xia下載,通過設定執行緒的數量,動態獲取下載檔案執行緒的個數,這是本人用於練習所寫demo,註釋很詳細,用於初學者參考使用。 MainActivity.java頁面   package com.dahui.download; import java.io.Buf

執行:performSelector:withObject:afterDelay:方法

面試題: 列印結果是:1、3 原因 performSelector:withObject:afterDelay:的本質是往Runloop中新增定時器 子執行緒預設沒有啟動Runloop 一、方法的含義 [self performSelector:@selector(t

Java 執行分段下載原理分析和實現

多執行緒下載介紹   多執行緒下載技術是很常見的一種下載方案,這種方式充分利用了多執行緒的優勢,在同一時間段內通過多個執行緒發起下載請求,將需要下載的資料分割成多個部分,每一個執行緒只負責下載其中一個部分,然後將下載後的資料組裝成完整的資料檔案,這樣便大大加快了下載效率。常見的下載器,迅

android執行暫停下載-HttpURLConnection

android多執行緒暫停下載-HttpURLConnection private EditText et_path; private LinearLayout ll_pbs; @Override protected void onCreate(Bundle sa