AsyncTask

AsyncTask是什么似将?

AsyncTask是Google推出的輕量級(jí)的異步處理工具屏积,本質(zhì)上就是一個(gè)封裝了線程池和handler的異步框架。

AsyncTask的用處宾舅?

實(shí)現(xiàn)多線程统阿,在工作線程中處理耗時(shí)任務(wù)同時(shí)會(huì)將工作線程中的結(jié)果傳遞到UI線程,不需要主動(dòng)去創(chuàng)建和操作線程彩倚。避免了對(duì)線程的維護(hù)和管理。

簡(jiǎn)單用法

// 三個(gè)泛型參數(shù)分別代表傳入的參數(shù)類型扶平,任務(wù)執(zhí)行過(guò)程需要更新的數(shù)據(jù)類型帆离,
//任務(wù)執(zhí)行結(jié)束返回的結(jié)果類型,如果無(wú)類型則可以用Void類
AsyncTask<Integer,Integer,Void> asyncTask = new AsyncTask<Integer, Integer, Void>() {
    /**
     * 得到結(jié)果结澄,在主線程執(zhí)行
     * @param aVoid
     */
    @Override
    protected void onPostExecute(Void aVoid) {
        Log.d(TAG, "onPostExecute: >>>");
        super.onPostExecute(aVoid);
    }

    /**
     * 任務(wù)內(nèi)容哥谷,在工作線程執(zhí)行
     * @param integers
     * @return
     */
    @Override
    protected Void doInBackground(Integer... integers) {
        Log.d(TAG, "doInBackground: >>>params: "+Arrays.toString(integers));
        return null;
    }

    /**
     * 任務(wù)執(zhí)行前,在主線程執(zhí)行
     */
    @Override
    protected void onPreExecute() {
        Log.d(TAG, "onPreExecute: >>");
        super.onPreExecute();
    }

    /**
     * 任務(wù)已取消(帶結(jié)果)麻献,在主線程執(zhí)行
     * @param aVoid
     */
    @Override
    protected void onCancelled(Void aVoid) {
        super.onCancelled(aVoid);
        Log.d(TAG, "onCancelled(有參): >>>");
    }

    /**
     * 任務(wù)已取消们妥,在主線程執(zhí)行
     */
    @Override
    protected void onCancelled() {
        super.onCancelled();
        Log.d(TAG, "onCancelled: >>>");
    }

    /**
     * 指定過(guò)程更新的數(shù)據(jù),在主線程執(zhí)行
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        Log.d(TAG, "onProgressUpdate: "+ Arrays.toString(values));
    }
};
asyncTask.execute(2,3,1);

AsyncTask的優(yōu)缺點(diǎn)赎瑰?

優(yōu)點(diǎn)
1王悍、方便實(shí)現(xiàn)異步通信破镰,不需要 Thread + Handler 復(fù)雜組合餐曼,同時(shí)節(jié)省資源,內(nèi)部采用線程池的緩存 + 復(fù)用模式鲜漩,避免了頻繁創(chuàng)建和銷毀線程帶來(lái)的系統(tǒng)資源開(kāi)銷源譬。
2、處理單個(gè)異步任務(wù)簡(jiǎn)單孕似,可以獲取到異步任務(wù)的進(jìn)度踩娘。
3、可以通過(guò)cancel方法取消還沒(méi)執(zhí)行完的AsyncTask喉祭。
缺點(diǎn)
1养渴、同時(shí)處理多個(gè)異步任務(wù)會(huì)降低效率。
2泛烙、如果在列表中大量創(chuàng)建和使用AsyncTask理卑,可能會(huì)出現(xiàn)因?yàn)楫惒饺蝿?wù)不能盡快完成任務(wù)導(dǎo)致一直在新開(kāi)線程去添加新的任務(wù),會(huì)造成滑動(dòng)不流暢蔽氨,當(dāng)開(kāi)啟的線程過(guò)多就會(huì)引起崩潰問(wèn)題藐唠。
3、如果使用AsyncTask去處理大量的異步任務(wù)并且使用的是異步線程池會(huì)有可能引起崩潰鹉究。崩潰異常:RejectedExecutionException

創(chuàng)建并執(zhí)行過(guò)多的AsyncTask導(dǎo)致創(chuàng)建大量的工作線程崩潰

AsyncTask中有一個(gè)全局靜態(tài)的線程池 -> SDK 28

static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            sPoolWorkQueue, sThreadFactory);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

線程池的配置:

//當(dāng)前虛擬機(jī)可用處理器數(shù)量
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
//我們希望在核心池中至少有2個(gè)線程宇立,最多4個(gè)線程,寧愿有1小于CPU計(jì)數(shù)自赔,以避免飽和
//具有后臺(tái)工作的CPU
//核心線程數(shù)量妈嘹,取決于獲取到的CPU核數(shù),最多4個(gè)線程數(shù)量
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大可用線程數(shù)绍妨,可用處理器數(shù)量的兩倍+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空閑線程超時(shí)時(shí)間
private static final int KEEP_ALIVE_SECONDS = 30;
//線程任務(wù)隊(duì)列容量128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

當(dāng)一個(gè)任務(wù)通過(guò)execute方法把任務(wù)加入到線程池時(shí)蟋滴;這是ThreadPoolExecutor特性染厅;

  • 如果此時(shí)線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài)津函,也要?jiǎng)?chuàng)建新的線程來(lái)處理被添加的任務(wù)肖粮。
  • 如果此時(shí)線程池中的數(shù)量等于corePoolSize,但是緩沖隊(duì)列 workQueue未滿尔苦,那么任務(wù)被放入緩沖隊(duì)列涩馆。
  • 如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿允坚,并且線程池中的數(shù)量小于maximumPoolSize魂那,建新的線程來(lái)處理被添加的任務(wù)。
  • 如果此時(shí)線程池中的數(shù)量大于corePoolSize稠项,緩沖隊(duì)列workQueue滿涯雅,并且線程池中的數(shù)量等于maximumPoolSize,那么通過(guò) handler所指定的策略來(lái)處理此任務(wù)展运。
  • 當(dāng)線程池中的線程數(shù)量大于 corePoolSize時(shí)活逆,如果某線程(非核心線程)空閑時(shí)間超過(guò)keepAliveTime,線程將被終止拗胜。這樣蔗候,線程池可以動(dòng)態(tài)的調(diào)整池中的線程數(shù)。
//ThreadPoolExecutor添加任務(wù)
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     * 如果運(yùn)行的線程小于corePoolSize埂软,請(qǐng)嘗試執(zhí)行以下操作使用給定的命令啟動(dòng)一個(gè)新線程
     * 的任務(wù)锈遥。對(duì)addWorker的調(diào)用將自動(dòng)檢查runState和workerCount,這樣可以防止添加錯(cuò)誤警報(bào)
     * 當(dāng)它不應(yīng)該線程勘畔,通過(guò)返回false所灸。
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     * 如果一個(gè)任務(wù)可以成功排隊(duì),那么我們?nèi)匀恍枰俅螜z查我們是否應(yīng)該添加一個(gè)線程
     * (因?yàn)樯洗螜z查后現(xiàn)有的已經(jīng)死了)進(jìn)入此方法后炫七,池關(guān)閉爬立。所以我們重新檢查狀態(tài),
     * 如果需要诉字,回滾排隊(duì)停止懦尝,或者如果沒(méi)有新線程,則啟動(dòng)新線程
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     * 如果無(wú)法對(duì)任務(wù)排隊(duì)壤圃,則嘗試添加新線程陵霉。
     * 如果它失敗了,我們知道我們被關(guān)閉或飽和伍绳,因此拒絕任務(wù)踊挠。
     */
    int c = ctl.get();
    //1
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //2
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //3 -> 如果緩存數(shù)量超過(guò)了128,會(huì)拋出異常rejectedExecution
    else if (!addWorker(command, false))
        reject(command);
}

//異常
final void reject(Runnable command) {
    handler.rejectedExecution(command, this);
}

也就是:處理任務(wù)的優(yōu)先級(jí)為:
核心線程corePoolSize、任務(wù)隊(duì)列workQueue效床、最大線程maximumPoolSize睹酌,如果三者都滿了,使用handler處理被拒絕的任務(wù)(一般為拋出java.util.concurrent.RejectedExecutionException異常)剩檀。
ThreadPoolExecutor這個(gè)線程池都是進(jìn)程范圍共享的憋沿,static的,所以當(dāng)任務(wù)線程超過(guò)了緩存隊(duì)列的容量時(shí)也就是128個(gè)緩存數(shù)的情況下會(huì)拋出異常rejectedExecution沪猴。這個(gè)前提是使用異步線程池辐啄。不過(guò)從Android3.0開(kāi)始AsyncTask默認(rèn)使用的是同步線程池串行執(zhí)行,不會(huì)出現(xiàn)這個(gè)問(wèn)題运嗜。每一個(gè)AsyncTask一次只能執(zhí)行一個(gè)任務(wù)壶辜,也就是execute只能調(diào)用一次,在任務(wù)結(jié)束之前不能再次調(diào)用担租,要么就會(huì)報(bào)錯(cuò)砸民。
如果手動(dòng)切到到異步線程池執(zhí)行,那最多執(zhí)行corePoolSize數(shù)量的線程任務(wù)奋救,其他任務(wù)進(jìn)入阻塞狀態(tài)岭参。

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)");
        }
    }
...
}

同步線程池:

private static class SerialExecutor implements Executor {
    //使用一個(gè)集合來(lái)保證任務(wù)順序執(zhí)行,當(dāng)存在多個(gè)AsyncTask的時(shí)候菠镇,就是串行執(zhí)行
    //不能保證順序
    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);
        }
    }
}

因?yàn)橐淮涡灾荒軋?zhí)行corePoolSize(API 28 最大核心數(shù)量是4)數(shù)量的任務(wù)冗荸,其他的線程將進(jìn)入阻塞狀態(tài)承璃,這將極大地降低執(zhí)行效率利耍,這也就是大家推薦使用AsyncTask只用來(lái)執(zhí)行單個(gè)耗時(shí)任務(wù)的原因。
內(nèi)存泄漏
如果你自定義一個(gè)AsyncTask并且傳入了一個(gè)Activity的Context上下文環(huán)境盔粹,就很有可能引起這個(gè)問(wèn)題隘梨,AsyncTask和Activity的生命周期無(wú)關(guān),那么當(dāng)finish后舷嗡,AsyncTask依舊存在轴猎,而他持有著Activity的引用導(dǎo)致Activity無(wú)法被垃圾回收。
同時(shí)如果使用了非靜態(tài)匿名內(nèi)部類來(lái)實(shí)現(xiàn)AsyncTask进萄,由于Java內(nèi)部類的特點(diǎn)捻脖,他同樣會(huì)持有當(dāng)前Activity的引用造成內(nèi)存泄漏。
cancel方法問(wèn)題
傳入的參數(shù)表示當(dāng)前任務(wù)執(zhí)行時(shí)是否可以取消中鼠。但是當(dāng)你的doInBackground方法中執(zhí)行一個(gè)循環(huán)或者一個(gè)IO流讀寫任務(wù)可婶,即使你傳入了true,改方法也無(wú)法取消這個(gè)任務(wù)的執(zhí)行援雇。區(qū)別在于調(diào)用這個(gè)方法后矛渴,doInBackground執(zhí)行完成時(shí)會(huì)調(diào)用onCancelled方法,而不是onPostExecute方法惫搏,所以cancel無(wú)法保證任務(wù)能夠被及時(shí)取消具温。

mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
        mTaskInvoked.set(true);
        Result result = null;
        try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            //這個(gè)方法執(zhí)行完后才回去判斷是否取消任務(wù)的執(zhí)行
            //所以cancel無(wú)法保證任務(wù)能夠及時(shí)被取消
            result = doInBackground(mParams);
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            //也就是只要執(zhí)行到doInBackground那必然會(huì)執(zhí)行到這個(gè)方法
            postResult(result);
        }
        return result;
    }
};
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;
        }
    }
}
private void finish(Result result) {
    //這個(gè)時(shí)候只能在onPostExecute之前才能取消蚕涤,不過(guò)任務(wù)都已經(jīng)做完了,結(jié)果都拿到了
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

AsyncTask的原理铣猩?

一揖铜、創(chuàng)建AsyncTask

AsyncTask<String,Integer,Boolean> asyncTask = new AsyncTask();

構(gòu)造方法

public AsyncTask(@Nullable Looper callbackLooper) {
    //創(chuàng)建一個(gè)主線程的Handler,用來(lái)把結(jié)果和進(jìn)入返回到主線程的回調(diào)中
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);
    //處理異步任務(wù)
    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                //執(zhí)行此回調(diào)
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };
    //一個(gè)可以取消的任務(wù)
    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 occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

初始化線程池和相關(guān)配置

//當(dāng)前虛擬機(jī)可用處理器數(shù)量
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
//我們希望在核心池中至少有2個(gè)線程达皿,最多4個(gè)線程蛮位,寧愿有1小于CPU計(jì)數(shù),以避免飽和
//具有后臺(tái)工作的CPU
//核心線程數(shù)量鳞绕,取決于獲取到的CPU核數(shù)失仁,最多4個(gè)線程數(shù)量
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
//最大可用線程數(shù),可用處理器數(shù)量的兩倍+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
//空閑線程超時(shí)時(shí)間 30s
private static final int KEEP_ALIVE_SECONDS = 30;
//線程任務(wù)隊(duì)列容量128
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);
      
/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 * 可以用來(lái)并行執(zhí)行任務(wù)的{@link Executor}们何。
 * 異步線程池萄焦,并行執(zhí)行任務(wù)
 */
public static final Executor THREAD_POOL_EXECUTOR;  
static {
    //靜態(tài)代碼塊初始化線程池并配置相關(guān)參數(shù)
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            sPoolWorkQueue, sThreadFactory);
    threadPoolExecutor.allowCoreThreadTimeOut(true);
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

/**
 * An {@link Executor} that executes tasks one at a time in serial
 * order.  This serialization is global to a particular process.
 * 同步線程池,串行執(zhí)行任務(wù)冤竹,內(nèi)部維護(hù)一個(gè)線程隊(duì)列來(lái)保證順序執(zhí)行任務(wù)
 */
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

二拂封、執(zhí)行AsyncTask

//默認(rèn)串行執(zhí)行任務(wù)
asyncTask.execute("result");
or
//使用并行執(zhí)行任務(wù)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"result");

#AsyncTask
@MainThread -> 在主線程中執(zhí)行
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

最終會(huì)執(zhí)行到

@MainThread -> 在主線程中執(zhí)行
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;
    //最開(kāi)始會(huì)執(zhí)行此方法回調(diào),告訴我們?nèi)蝿?wù)執(zhí)行前的準(zhǔn)備工作鹦蠕。
    onPreExecute();
    mWorker.mParams = params;
    //通過(guò)此方法開(kāi)啟線程執(zhí)行任務(wù)
    exec.execute(mFuture);
    return this;
}

可以看到一個(gè)AsyncTask一次只能執(zhí)行一個(gè)任務(wù)冒签,在任務(wù)結(jié)束之前如果再次調(diào)用execute或者executeOnExecutor方法會(huì)拋出異常。
exec -> 默認(rèn)的是SerialExecutor钟病,也可以主動(dòng)設(shè)置THREAD_POOL_EXECUTOR -> ThreadPoolExecutor
mFuture -> FutureTask<WorkerRunnable> -> mFuture就是mWorker的一個(gè)包裝類萧恕,它也具體實(shí)現(xiàn)了Future的一些任務(wù)操作接口,比如取消任務(wù)肠阱,mFuture重寫了done()方法票唆,應(yīng)該是考慮到AsyncTask的get()和cancel()方法內(nèi)部出異常時(shí)對(duì)結(jié)果的處理。
WorkerRunnable -> 這個(gè)就是真正執(zhí)行異步任務(wù)的
默認(rèn)執(zhí)行的是串行任務(wù)

private static class SerialExecutor implements Executor {
    //使用一個(gè)集合來(lái)保證任務(wù)順序執(zhí)行屹徘,當(dāng)存在多個(gè)AsyncTask的時(shí)候走趋,就是串行執(zhí)行
    //不能保證順序
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchronized void execute(final Runnable r) {
        // 入隊(duì)一個(gè)runnable,對(duì)原始的runnable加了點(diǎn)修飾
        mTasks.offer(new Runnable() {
            public void run() {
                try {
                    r.run();
                } finally {
                    // 任務(wù)執(zhí)行后,要檢查是否有下一個(gè)runnable需要執(zhí)行
                    scheduleNext();
                }
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }
    //檢查是否有下一個(gè)runnable需要執(zhí)行噪伊,如果有簿煌,則交給另一個(gè)線程池執(zhí)行
    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            //最終通過(guò)此方法把任務(wù)放入到線程池中
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

并行任務(wù)就是直接使用調(diào)用放入到線程池中

THREAD_POOL_EXECUTOR.execute(mActive);
//也就是
executeOnExecutor(){
  //exec這就是THREAD_POOL_EXECUTOR
  exec.execute(mFuture);
}

線程池添加任務(wù),根據(jù)執(zhí)行規(guī)則分為以下幾點(diǎn):

  • 當(dāng)一個(gè)任務(wù)通過(guò)execute方法把任務(wù)加入到線程池時(shí)鉴吹;這是ThreadPoolExecutor特性姨伟;
  • 如果此時(shí)線程池中的數(shù)量小于corePoolSize,即使線程池中的線程都處于空閑狀態(tài)拙寡,也要?jiǎng)?chuàng)建新的線程來(lái)處理被添加的任務(wù)授滓。
  • 如果此時(shí)線程池中的數(shù)量等于corePoolSize,但是緩沖隊(duì)列 workQueue未滿,那么任務(wù)被放入緩沖隊(duì)列般堆。
  • 如果此時(shí)線程池中的數(shù)量大于corePoolSize在孝,緩沖隊(duì)列workQueue滿,并且線程池中的數(shù)量小于maximumPoolSize淮摔,建新的線程來(lái)處理被添加的任務(wù)私沮。
  • 如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿和橙,并且線程池中的數(shù)量等于maximumPoolSize仔燕,那么通過(guò) handler所指定的策略來(lái)處理此任務(wù)。
  • 當(dāng)線程池中的線程數(shù)量大于 corePoolSize時(shí)魔招,如果某線程(非核心線程)空閑時(shí)間超過(guò)keepAliveTime晰搀,線程將被終止。這樣办斑,線程池可以動(dòng)態(tài)的調(diào)整池中的線程數(shù)外恕。
//ThreadPoolExecutor添加任務(wù)
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     * 如果運(yùn)行的線程小于corePoolSize,請(qǐng)嘗試執(zhí)行以下操作使用給定的命令啟動(dòng)一個(gè)新線程
     * 的任務(wù)乡翅。對(duì)addWorker的調(diào)用將自動(dòng)檢查runState和workerCount鳞疲,這樣可以防止添加錯(cuò)誤警報(bào)
     * 當(dāng)它不應(yīng)該線程,通過(guò)返回false蠕蚜。
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     * 如果一個(gè)任務(wù)可以成功排隊(duì)尚洽,那么我們?nèi)匀恍枰俅螜z查我們是否應(yīng)該添加一個(gè)線程
     * (因?yàn)樯洗螜z查后現(xiàn)有的已經(jīng)死了)進(jìn)入此方法后,池關(guān)閉靶累。所以我們重新檢查狀態(tài)腺毫,
     * 如果需要,回滾排隊(duì)停止尺铣,或者如果沒(méi)有新線程拴曲,則啟動(dòng)新線程
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     * 如果無(wú)法對(duì)任務(wù)排隊(duì)争舞,則嘗試添加新線程凛忿。
     * 如果它失敗了,我們知道我們被關(guān)閉或飽和竞川,因此拒絕任務(wù)店溢。
     */
    int c = ctl.get();
    //1
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //2
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //3 -> 如果緩存數(shù)量超過(guò)了128,會(huì)拋出異常rejectedExecution
    else if (!addWorker(command, false))
        reject(command);
}

//異常
final void reject(Runnable command) {
    handler.rejectedExecution(command, this);
}

緩存池的容量最多128委乌,如果大于此數(shù)量就會(huì)拋出異常java.util.concurrent.RejectedExecutionException拒絕再往里添加新的任務(wù)床牧。
至此,任務(wù)開(kāi)始執(zhí)行

mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
        mTaskInvoked.set(true);
        Result result = null;
        try {
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            //noinspection unchecked
            result = doInBackground(mParams);
            Binder.flushPendingCommands();
        } catch (Throwable tr) {
            mCancelled.set(true);
            throw tr;
        } finally {
            postResult(result);
        }
        return result;
    }
};
//Handler調(diào)用此方法通知主線程任務(wù)執(zhí)行完畢
private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

@Override
protected ReusableBitmap doInBackground(Void... params) {
    // enqueue the 'onDecodeBegin' signal on the main thread
    //執(zhí)行異步任務(wù)的同時(shí)回調(diào)相關(guān)進(jìn)度
    publishProgress();
    return decode();
}

@WorkerThread
protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        //進(jìn)度的回調(diào)會(huì)通過(guò)主線程的Handler發(fā)回給主線程
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

call()方法:首先mTaskInvoked是一個(gè)AtomicBoolean對(duì)象遭贸,它能保證線程安全地更新boolean值戈咳,mTaskInvoked.set(true)表示該AsyncTask對(duì)象已被調(diào)用。然后就是設(shè)置當(dāng)前線程的優(yōu)先級(jí)Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)。然后就是調(diào)用用戶實(shí)現(xiàn)的doInBackground(mParams)方法著蛙。然后Binder.flushPendingCommands();是一個(gè)native方法删铃,應(yīng)該是重新調(diào)整線程優(yōu)先級(jí)的。然后是捕獲異常踏堡,最后是通過(guò)postResult(result)提交結(jié)果到主線程猎唁。
執(zhí)行完畢

//Handler調(diào)用此方法通知主線程任務(wù)執(zhí)行完畢
private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

靜態(tài)內(nèi)部類生成了Handler

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
                //通知任務(wù)結(jié)束
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                //通知進(jìn)度
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

private void finish(Result result) {
    if (isCancelled()) {
        //取消任務(wù)
        onCancelled(result);
    } else {
        //結(jié)束任務(wù)并獲得結(jié)果
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

至此AsyncTask的執(zhí)行到此為止。
可以發(fā)現(xiàn)AsyncTask中存在兩個(gè)線程池:
ThreadPoolExecutor:用來(lái)執(zhí)行任務(wù)
SerialExecutor:用來(lái)處理任務(wù)列表

AsyncTask的問(wèn)題顷蟆?

為什么用兩個(gè)線程池诫隅?
因?yàn)锳syncTask是設(shè)計(jì)為串行執(zhí)行任務(wù)的,所以另外最好需要一個(gè)線程池負(fù)責(zé)任務(wù)的排隊(duì)帐偎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末逐纬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子削樊,更是在濱河造成了極大的恐慌风题,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嫉父,死亡現(xiàn)場(chǎng)離奇詭異沛硅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)绕辖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門摇肌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人仪际,你說(shuō)我怎么就攤上這事围小。” “怎么了树碱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵肯适,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我成榜,道長(zhǎng)框舔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任赎婚,我火速辦了婚禮刘绣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挣输。我一直安慰自己纬凤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布撩嚼。 她就那樣靜靜地躺著停士,像睡著了一般挖帘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恋技,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天肠套,我揣著相機(jī)與錄音,去河邊找鬼猖任。 笑死你稚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的朱躺。 我是一名探鬼主播刁赖,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼长搀!你這毒婦竟也來(lái)了宇弛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤源请,失蹤者是張志新(化名)和其女友劉穎枪芒,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谁尸,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舅踪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了良蛮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抽碌。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖决瞳,靈堂內(nèi)的尸體忽然破棺而出货徙,到底是詐尸還是另有隱情,我是刑警寧澤皮胡,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布痴颊,位于F島的核電站,受9級(jí)特大地震影響屡贺,放射性物質(zhì)發(fā)生泄漏蠢棱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一烹笔、第九天 我趴在偏房一處隱蔽的房頂上張望裳扯。 院中可真熱鬧,春花似錦谤职、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冤吨。三九已至,卻和暖如春饶套,著一層夾襖步出監(jiān)牢的瞬間漩蟆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工妓蛮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怠李,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓蛤克,卻偏偏與公主長(zhǎng)得像捺癞,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子构挤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 雖說(shuō)現(xiàn)在做網(wǎng)絡(luò)請(qǐng)求有了Volley全家桶和OkHttp這樣好用的庫(kù)筋现,但是在處理其他后臺(tái)任務(wù)以及與UI交互上唐础,還是需...
    weishu閱讀 3,362評(píng)論 10 55
  • 什么是線程池?為什么要用線程池矾飞?Java中的線程池是運(yùn)用場(chǎng)景最多的并發(fā)框架一膨,幾乎所有需要異步或并發(fā)執(zhí)行任務(wù)的程序都...
    stevefat閱讀 464評(píng)論 0 0
  • 由于經(jīng)常遇到AsyncTask,感覺(jué)功能比較簡(jiǎn)單洒沦,不成想過(guò)總結(jié)一下汞幢,現(xiàn)在感覺(jué)自己還是不要太懶,逼自己寫下微谓,總結(jié)一下...
    小毛驢Jim閱讀 929評(píng)論 0 0
  • android對(duì)于主線程的響應(yīng)時(shí)間限制的非常嚴(yán)格豺型,稍有不慎就會(huì)遇到Application Not Respondi...
    uncle_charlie閱讀 895評(píng)論 1 13
  • 最近找實(shí)習(xí)面試中經(jīng)常會(huì)被問(wèn)到關(guān)于AsyncTask的一些內(nèi)部機(jī)制的問(wèn)題仲智,之前也早有學(xué)習(xí),但是還不夠系統(tǒng)姻氨,沒(méi)有形成一...
    水煮米茶閱讀 2,819評(píng)論 0 6