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ì)帐偎。