[TOC]
## 1、串行還是并行
實際后臺線程只有一個,即所有的任務是串行的,即完成一個任務后再執行下一個任務,而非并行。
如果開多個任務,比如開三個任務,實際執行是串行的:
```
mAsyncTask task1 = new mAsyncTask();
mAsyncTask task2 = new mAsyncTask();
mAsyncTask task3 = new mAsyncTask();
task1.execute("1", "2", "3");
task2.execute("a", "b", "c");
task3.execute("x", "y", "z");
```
期望是任務線程并行的,如下:

而實際情況是所有的線程都是串行的:

異步任務是串行的,那么能不能并行呢?查閱資料發現是可以的。
在1.6之前,AsyncTask是串行執行任務的,1.6的時候AsyncTask開始采用線程池里處理并行任務,但是從3.0開始,為了避免AsyncTask所帶來的并發錯誤,AsyncTask可以根據配置采用串行或并行執行任務,但是默認是采用一個線程來串行執行任務,若想并行執行任務,可以調用 executeOnExecutor (Executor exec, Params... params)方法。
該方法有兩個參數,第一個是Executor ,第二個是任務參數,第一個是線程池實例,這里已經預定義了兩種,AsyncTask.SERIAL_EXECUTOR和AsyncTask.THREAD_POOL_EXECUTOR,通過源代碼可以看到,execute (Params... params)方法實際是調用的就是executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params),即串行執行,如果想并行執行異步任務,可調用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params)方法。
## 2、任務線程過多
異步任務并行處理時,AsyncTask最多可以同時執行的任務數量有限,同時隊列中可以有128個在等待。 如果超過這個數字,就會報java.util.concurrent.RejectedExecutionException的異常(超出線程池容量以及隊列長度后拒絕任務的策略)。
AsyncTask.THREAD_POOL_EXECUTOR線程池的配置如下:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
其中:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));//設置線程池的核心線程數2-4之間,但是取決于CPU核數
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;//最多工作線程數量
private static final int KEEP_ALIVE_SECONDS = 30;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);//等待隊列,等待128個
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
所以AsyncTask可能存在新開大量線程消耗系統資源和拋出異常,如沒有捕獲RejectedExecutionException異常會導致應用FC的風險。
訪問網絡頻繁或者需要大量線程的程序應慎用AsyncTask。
## 3、生命周期
AsyncTask不與任何組件綁定生命周期,即在一個Activity中創建AsyncTask,當該Activity被銷毀時AsyncTask并沒有被同步銷毀,而是在一直執行,直到doInBackground()方法執行完成。如果手動調用了cancel()方法,系統會自動調用onCancelled()方法,否則會執行onPostExecute()方法。
所以這里就會產生一個問題,Activity已經被銷毀,而AsyncTask還在正常工作,還會對View做一些處理,但是此時的View已經不存在了。
所以應該確保在銷毀Activity的同時,取消AsyncTask,即在Activity的onDestory()內調用cancel()方法。
## 4、任務執行結果丟失問題
當Activity重新創建時(屏幕旋轉時或Activity意外銷毀時恢復),AsyncTask任務正常運行,AsyncTask持有的銷毀之前的Activity引用已經無效,而AsyncTask任務執行完成后,在onPostExecute()方法內修改UI也不會生效。
所以最好的辦法是,當恢復Activity時重啟AsyncTask任務。
## 5、內存泄漏
如果AsyncTask被聲明為Activity的非靜態內部類,那么AsyncTask會默認保留一個對該Activity的引用,如果這個Activity已經被銷毀,因這種引用關系的存在,造成該Activity無法被回收,造成內存泄漏。
## 參考資料
[ AsyncTask存在的問題和缺陷](https://blog.csdn.net/haovin/article/details/90343595)
- Android
- 四大組件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介紹
- MessageQueue詳細
- 啟動流程
- 系統啟動流程
- 應用啟動流程
- Activity啟動流程
- View
- view繪制
- view事件傳遞
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大數據
- Binder小結
- Android組件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 遷移與修復
- Sqlite內核
- Sqlite優化v2
- sqlite索引
- sqlite之wal
- sqlite之鎖機制
- 網絡
- 基礎
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP進化圖
- HTTP小結
- 實踐
- 網絡優化
- Json
- ProtoBuffer
- 斷點續傳
- 性能
- 卡頓
- 卡頓監控
- ANR
- ANR監控
- 內存
- 內存問題與優化
- 圖片內存優化
- 線下內存監控
- 線上內存監控
- 啟動優化
- 死鎖監控
- 崩潰監控
- 包體積優化
- UI渲染優化
- UI常規優化
- I/O監控
- 電量監控
- 第三方框架
- 網絡框架
- Volley
- Okhttp
- 網絡框架n問
- OkHttp原理N問
- 設計模式
- EventBus
- Rxjava
- 圖片
- ImageWoker
- Gilde的優化
- APT
- 依賴注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 協程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 運行期Java-hook技術
- 編譯期hook
- ASM
- Transform增量編譯
- 運行期Native-hook技術
- 熱修復
- 插件化
- AAB
- Shadow
- 虛擬機
- 其他
- UI自動化
- JavaParser
- Android Line
- 編譯
- 疑難雜癥
- Android11滑動異常
- 方案
- 工業化
- 模塊化
- 隱私合規
- 動態化
- 項目管理
- 業務啟動優化
- 業務架構設計
- 性能優化case
- 性能優化-排查思路
- 性能優化-現有方案
- 登錄
- 搜索
- C++
- NDK入門
- 跨平臺
- H5
- Flutter
- Flutter 性能優化
- 數據跨平臺