AsyncTask分析筆記

AsyncTask. execute(Params… params)
params這個參數就是入參。異步執行任務的時候需要用到的參數可以用這個params傳入。在這個方法可以接受到傳入的參數。protected String doInBackground(Params… params)

這個execute(Params… params)方法的源碼:裏面去調用一個executeOnExecutor(sDefauItExecutor,params);
public final AsyncTask<Params, Progress, Result> execute(Params… params) {
return executeOnExecutor(sDefaultExecutor, params);
}
看看sDefauItExecutor是個什麼東西,AsyncTask裏面有一句這樣的代碼。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

再看看SERIAL_EXECUTOR 是什麼?它是一個SerialExecutor這個可以暫時不管
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

回來看看executeOnExecutor(sDefaultExecutor, params);裏面做了什麼:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params… params) {
//if語句裏面做了一個異常的判斷。如果正在運行的會拋出這個任務已經在運行。如果是運行結束的,再重新運行的話會拋出這個任務只能運行異常。 所以我們不能同時執行一個任務。
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。mWorker是一個WorkerRunnable它是實現了Callabler的接口。
mWorker.mParams = params;
//exec是我們傳入的。上面SERIAL_EXECUTOR就是這個exec。 exec.execute(mFuture)(mFuture是一個FutureTask)。
exec.execute(mFuture);
return this;
}

從上面mWorker.mParams= params 和exec.execute(mFuture)可以猜到這裏的線程創建方式是Callable+FutureTask+Thread的方式。這種創建方式的好處是,線程結束後可以得到一個返回值結果。

看看exec.execute(mFuture)裏面做了什麼。
因爲exec是一個SerialExecutor。所以這裏直接貼出了它的代碼。它是AsyncTask的一個靜態內部類。

private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
//這裏出入的是一個Runnable。上面的mFuture是FutureTask,FutureTask實現了Runnable接口。所以可以直接傳進來。
public synchronized void execute(final Runnable r) {
mTasks是一個ArrayDeque它是一個雙端隊列(支持對頭插入或者隊尾插入) mTasks.offer()是在隊尾插入。
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
//如果沒有任務在執行。
if (mActive == null) {
scheduleNext();
}
}

    protected synchronized void scheduleNext() {
    //mTasks.poll()從對頭中取出一個任務。如果有任務的話。
        if ((mActive = mTasks.poll()) != null) {
        //線程池就去執行mActive這個任務 ,THREAD_POOL_EXECUTOR是一個線程池。 看下面
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}
//THREAD_POOL_EXECUTOR在這裏。
public static final Executor THREAD_POOL_EXECUTOR;
static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), sThreadFactory);
    threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
  //  主要是這句。 這個靜態代碼塊是用於創建線程池的。
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

看看創建線程池的參數:
CORE_POOL_SIZE 核心線程數:這個值是1.
MAXIMUM_POOL_SIZE 最大線程數 :這個值是20
KEEP_ALIVE_SECONDS在沒有任務的情況下線程存活的時間是3
TimeUnit.SECONDS 存活的時間單位是秒。意思是存活3秒就會被回收掉。
new SynchronousQueue SynchronousQueue沒有容量,是無緩衝等待隊列,是一個不存儲元素的阻塞隊列,會直接將任務交給消費者,必須等隊列中的添加元素被消費後才能繼續添加新的元素。

擁有公平(FIFO)和非公平(LIFO)策略,非公平側羅會導致一些數據永遠無法被消費的情況?

使用SynchronousQueue阻塞隊列一般要求maximumPoolSizes爲無界(Integer.MAX_VALUE),避免線程拒絕執行操作。
sThreadFactory這個是創建線程的工廠
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);這裏是設置拒絕任務的策略。

sRunOnSerialPolicy是什麼東西?
//這裏就是拒絕策略。簡單來說就是上面創建的線程池不夠用了就會觸發這個拒絕策略的執行。因爲上面使用的是SynchronousQueue並且最大線程數只設置了爲20.所以很容易觸發這裏的拒絕策略。
private static ThreadPoolExecutor sBackupExecutor;
private static LinkedBlockingQueue sBackupExecutorQueue;
private static final RejectedExecutionHandler sRunOnSerialPolicy =
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
android.util.Log.w(LOG_TAG, “Exceeded ThreadPoolExecutor pool size”);
// As a last ditch fallback, run it on an executor with an unbounded queue.
// Create this executor lazily, hopefully almost never.
synchronized (this) {
if (sBackupExecutor == null) {
//這裏使用的隊列因爲沒有設置隊列長度,默認是Integer.MAX_VALUE所以會有內存溢出的風險
sBackupExecutorQueue = new LinkedBlockingQueue();
//觸發拒絕策略之後,這裏實現了一個自定義拒絕策略。 然後又創建了一個線程池去處理。這裏創建的線程池的拒絕策略使用了默認的。因爲這裏創建的時候並沒有指定拒絕策略,所以系統會使用默認的。private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

sBackupExecutor = new ThreadPoolExecutor( BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,TimeUnit.SECONDS,sBackupExecutorQueue, sThreadFactory);
//當任務空閒的時候,等待時間超過了設置的等待時間就關閉空閒的線程 sBackupExecutor.allowCoreThreadTimeOut(true);
}
}
//啓用新的線程池去執行任務。
sBackupExecutor.execute®;
}
};

//線程池裏面執行的任務就是這個
mFuture = new FutureTask(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 occurred while executing doInBackground()”,
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
看postResultIfNotInvoked(get)方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();//這裏取到正在任務是否被調用了。
if (!wasTaskInvoked) {
postResult(result);
}
}
//如果任務沒有被消耗:
private Result postResult(Result result) {
@SuppressWarnings(“unchecked”)
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();//發送handler消息
return result;
}
看看getHandler
private Handler getHandler() {
return mHandler;
}
//再看看handler是怎麼創建的。這裏創建的是一個主線程的handler。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
全程只用到了主線程的handler。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章