有關AsyncTask的一些隨筆筆記

一個暱稱而已T發表於2017-09-22

今天在做有關AsyncTask的題目的時候,突發奇想,要是在子執行緒中初始化一個AsyncTask例項,其各個方法是執行在什麼執行緒中的。

下面

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("new Thread", "currentThread="+Thread.currentThread());
                new MyTask().execute();
            }
        }).start();
    }

    private class MyTask extends AsyncTask<Void, Integer, String> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.d("onPreExecute", "currentThread="+Thread.currentThread());
        }

        @Override
        protected String doInBackground(Void... voids) {
            Log.d("doInBackground", "currentThread="+Thread.currentThread());
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                publishProgress(1);
            }
            return "END";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            Log.d("onProgressUpdate", "currentThread="+Thread.currentThread());
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            Log.d("onPostExecute", "currentThread=" + Thread.currentThread());
        }
    }

}

然後是執行結果:
這裡寫圖片描述

可以看出,要是是在子執行緒中初始化一個AsyncTask並執行,只有onPreExecute()方法是線上程中執行的,而doInBackground與平時沒有區別,是在自己內部維護的執行緒執行,而onProgressUpdateonPostExecute還是在主執行緒中執行。


另外,如果同時執行多個AsyncTask的話,他們預設是序列執行,因為在整個應用程式中的所有AsyncTask例項都會共用同一個SerialExecutor以及THREAD_POOL_EXECUTOR。(在AsyncTask中這兩個都是類變數,用static修飾的)


AsyncTask中有兩個實現了Executor介面的類,一個是SerialExecutor,另一個是THREAD_POOL_EXECUTOR,很多文章中說SerialExecutor也是一個執行緒池,但就個人的觀點而言,這麼說應該是不準確的,因為在這個類裡面並沒建立執行緒,而Executor介面的作用如下:
(關於這一點,歡迎交流討論。)

執行提交的Runnable任務的物件。這個介面提供了一種將任務提交與每個任務如何執行的機制解耦的方法,包括執行緒使用,排程等細節。

其中SerialExecutor是用來讓所有任務序列取出, 而ThreadPoolExecutor用於執行指定的任務,在最初的 AsyncTask 中只支援序列工作,後在3.0之後加入了executeOnExecutor方法,該方法提供並行了並行操作,一般而言用法為 ,其引數也可以為自定義的執行緒池。

new AsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"...");

SerialExecutor使任務序列執行的,每個任務還是提交到THREAD_POOL_EXECUTOR 執行緒池中來執行,但只能等上一個執行完,才能提交下一個,因此執行緒池中永遠只有一個任務在執行,當然,可能上一個任務執行完會,執行緒空閒時間還沒超出1秒,這樣就不會被移除執行緒池,線上程數量小於corePoolSize時,會再次建立一個執行緒放入執行緒池來執行新的任務,即使有空閒執行緒,但是卻永遠只能有一個執行緒處於工作狀態。並不是說THREAD_POOL_EXECUTOR 不能併發,只是任務沒有併發提交到它。另外,要實現並行,可以用自定義的ThreadPoolExexutor,也可以用原始碼中提供的THREAD_POOL_EXECUTOR,它的coolPoolsize是CPU的數目+1,maximumPoolSize是2*cpu數目+1,keepAlive時間是1秒,阻塞佇列採用BlockingQueue,長度為128

相關文章