日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 默认站点!

默认站点

當前位置: 首頁 >

Android之AsyncTask两种线程池分析和总结

發布時間:2023/12/4 38 豆豆
默认站点 收集整理的這篇文章主要介紹了 Android之AsyncTask两种线程池分析和总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Android AsyncTask兩種線程池分析和總結
(一)? ? 前言
在android AsyncTask里面有兩種線程池供我們調用
1.? ? THREAD_POOL_EXECUTOR, 異步線程池
2.? ? SERIAL_EXECUTOR,同步線程池
正如上面名稱描述的那樣,一個是異步線程池,多個任務在線程池中并發執行;還有一個是同步執行的。
默認的話,直接調用execute的話,是使用SERIAL_EXECUTOR
下面的話,會用源代碼的方式來說明這兩種線程池的作用和注意事項。

(二)? ???THREAD_POOL_EXECUTOR用法舉例

private static int produceTaskMaxNumber = 500; 02public void dotask(){ 03for (int i = 1; i <= produceTaskMaxNumber; i++){ 04// 產生一個任務,并將其加入到線程池 05String task = "task@ " + i; 06Log.d("Sandy", "put " + task); 07MyAsyncTask asynct = new MyAsyncTask(task); 08asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0); 09} 10} 1112static class MyAsyncTask extends AsyncTask<Integer, Integer, Integer>{ 13private static int consumeTaskSleepTime = 2000; 14// 保存任務所需要的數據 15private Object threadPoolTaskData; 16public MyAsyncTask(String s){ 17threadPoolTaskData = s; 18} 19<a href="http://home.51cto.com/index.php?s=/space/5017954" target="_blank">@Override</a> 20protected Integer doInBackground(Integer... arg0) { 21Log.d("Sandy", "start .." + threadPoolTaskData 22+ " thread id: " + Thread.currentThread().getId() 23+ " thread name: " + Thread.currentThread().getName()); 24try { 25// //便于觀察,等待一段時間 26Thread.sleep(consumeTaskSleepTime); 27} 28catch (Exception e) { 29Log.d("Sandy", "", e); 30} 31threadPoolTaskData = null; 32return 0; 33} 34}2.? ? 使用方法比較簡單,首先創建一個繼承自AsyncTask的MyAsyncTask類,然后調用

MyAsyncTask asynct = new MyAsyncTask(task); 2asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0);就可以了。
3.? ? 上面代碼執行的時候會出錯,導致程序異常終止,如下圖

就是因為我們嘗試添加500個task到AsyncTask.THREAD_POOL_EXECUTOR線程池中,但是它的核心線程是5,隊列容量是128,最大線程數是9。
所以,拋出了這個異常。
那么,接下來的話,我們會去分析這個異常怎么出來的。

(三)? ???THREAD_POOL_EXECUTOR代碼分析
從AsyncTask.THREAD_POOL_EXECUTOR的定義開始分析
1.? ? 代碼路徑
frameworks\base\core\java\android\os\AsyncTask.java
代碼:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 02private static final int CORE_POOL_SIZE = CPU_COUNT + 1; 03private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; 04private static final int KEEP_ALIVE = 1; 0506.... 07/** 08* An {@link Executor} that can be used to execute tasks in parallel. 09*/ 10public static final Executor THREAD_POOL_EXECUTOR 11= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 12TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);它的幾個參數CORE_POOL_SIZE, MAXIMUN_POOL_SIZE, 都是根據當前手機的處理器數量進行動態定義的。
那么,繼續往下面看,看這幾個參數傳進去后是什么意思。
2.? ? 代碼路徑
\libcore\luni\src\main\java\java\util\concurrent\ThreadPoolExecutor.java
代碼:

public ThreadPoolExecutor(int corePoolSize, 02int maximumPoolSize, 03long keepAliveTime, 04TimeUnit unit, 05BlockingQueue<Runnable> workQueue, 06ThreadFactory threadFactory, 07RejectedExecutionHandler handler) { 08if (corePoolSize < 0 || 09maximumPoolSize <= 0 || 10maximumPoolSize < corePoolSize || 11keepAliveTime < 0) 12throw new IllegalArgumentException(); 13if (workQueue == null || threadFactory == null || handler == null) 14throw new NullPointerException(); 15this.corePoolSize = corePoolSize; 16this.maximumPoolSize = maximumPoolSize; 17this.workQueue = workQueue; 18this.keepAliveTime = unit.toNanos(keepAliveTime); 19this.threadFactory = threadFactory; 20this.handler = handler; 21} 2223/** 24* The default rejected execution handler 25*/ 26private static final RejectedExecutionHandler defaultHandler = 27new AbortPolicy();
這是ThreadPoolExecutor的構造函數,首先需要明白的是這幾個參數的含義
A.? ? corePoolSize: 線程池維護線程的最少數量
B.? ? maximumPoolSize:線程池維護線程的最大數量
C.? ? keepAliveTime: 線程池維護線程所允許的空閑時間
D.? ? unit: 線程池維護線程所允許的空閑時間的單位
E.? ? workQueue: 線程池所使用的緩沖隊列
F.? ? handler: 線程池對拒絕任務的處理策略

當一個任務通過asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0)方法欲添加到線程池時:
如果此時線程池中的數量小于corePoolSize,即使線程池中的線程都處于空閑狀態,也要創建新的線程來處理被添加的任務。
如果此時線程池中的數量等于 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
如果此時線程池中的數量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數量小于maximumPoolSize,建新的線程來處理被添加的任務。
如果此時線程池中的數量大于corePoolSize,緩沖隊列workQueue滿,并且線程池中的數量等于maximumPoolSize,那么通過 handler所指定的策略來處理此任務。

也就是:處理任務的優先級為:
核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。

當線程池中的線程數量大于 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。

unit可選的參數為java.util.concurrent.TimeUnit中的幾個靜態屬性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue是BlockQueue的子類,ArrayBlockingQueue,DelayQueue

handler有四個選擇(這不是android的Handler):
ThreadPoolExecutor.AbortPolicy() – 這個也是AsyncTask.THREAD_POOL_EXECUTOR使用的
拋出java.util.concurrent.RejectedExecutionException異常
ThreadPoolExecutor.CallerRunsPolicy()
重試添加當前的任務,他會自動重復調用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()
拋棄舊的任務
ThreadPoolExecutor.DiscardPolicy()
拋棄當前的任務

所以,正是我們的AsyncTask.THREAD_POOL_EXECUTOR使用了AbortPolicy()類型的handler,所以才會拋出異常..

那么,在把任務添加到AsyncTask.THREAD_POOL_EXECUTOR之后,下面的工作就是由這個線程池來調度線程執行任務了。

(四)? ???AsyncTask. SERIAL_EXECUTOR
1.? ? 使用方法
AsyncTask. SERIAL_EXECUTOR的使用方法和Async.THREAD_POOL_EXECUTOR差不多。不過正如前面所說,它是默認的Executor,所以可以直接調用,所以可以有兩種調用方法。

1a.? ? asynct.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, 0);
2b.? ? asynct.execute(0);
效果是一樣的

2.執行流程
代碼路徑:
frameworks\base\core\java\android\os\AsyncTask.java
代碼:
01public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
02???? ?? ?? ?Params... params) {
03???? ???...
04???? ???exec.execute(mFuture);
05???? ???....
06}
07?
08private static class SerialExecutor implements Executor {
09???? ???final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
10???? ???Runnable mActive;
11???? ???public synchronized void execute(final Runnable r) {
12???? ?? ?? ?mTasks.offer(new Runnable() {
13???? ?? ?? ?? ? public void run() {
14???? ?? ?? ?? ?? ???try {
15???? ?? ?? ?? ?? ?? ?? ?r.run();
16???? ?? ?? ?? ?? ???} finally {
17???? ?? ?? ?? ?? ?? ?? ?scheduleNext();
18???? ?? ?? ?? ?? ???}
19???? ?? ?? ?? ? }
20???? ?? ?? ?});
21???? ?? ?? ?if (mActive == null) {
22???? ?? ?? ?? ? scheduleNext();
23???? ?? ?? ?}
24???? ???}
25?
26???? ???protected synchronized void scheduleNext() {
27???? ?? ?? ?if ((mActive = mTasks.poll()) != null) {
28???? ?? ?? ?? ? THREAD_POOL_EXECUTOR.execute(mActive);
29???? ?? ?? ?}
30???? ???}
31??? }
嗯,它會調用到SerialExecutor.execute(Runnable r)方法
在這個方法里面,它首先把任務放到mTasks這個集合里面;然后判斷mActivie是否為空,再調用scheduleNext ()方法。
mActivie為null的意思是當前沒有任務在執行,如果mActivie!=null,那么說明當前有任務正在執行,那么只要把任務添加到mTasks里面即可。
因為任務執行完畢后,會再次調用scheduleNext()方法的,就是
finally {
? ?? ???scheduleNext();
? ???}
這樣就形成了一種鏈狀調用結構,只要mTasks里面還有任務,就會不斷逐一調用,如果后面有任務進來,就只要添加到mTasks里面即可。
同時,不知道大家注意到沒有,這兩個方法都是synchronized的,這樣,就保證了多線程之間調度問題。
否則肯定會出現問題的,至于什么問題,大家想想就能明白。

4.? ? 繼續分析scheduleNext()方法
這個方法首先把mTasks里面的數據取一個出來,然后調用
THREAD_POOL_EXECUTOR.execute(mActive);
我暈,這不就是上面一直在分析的AsyncTask.THREAD_POOL_EXECUTOR么?
好吧,原來AsyncTask.THREAD_POOL_EXECUTOR和AsyncTask.SERIAL_EXECUTOR的區別就是SERIAL_EXECUTOR在THREAD_POOL_EXECUTOR的基礎上添加了一個mTasks的集合來保證任務順序執行而已...

(五)? ???總結
說了這么多,總結下
1.? ? AsyncTask里面有THREAD_POOL_EXECUTOR和SERIAL_EXECUTOR兩種方式來異步執行任務;THREAD_POOL_EXECUTOR是異步的,而SERIAL_EXECUTOR任務是順序執行的。
2.? ? THREAD_POOL_EXECUTOR如果添加的任務過多,沒有及時處理的話,會導致程序崩潰,它的隊列size是128;它的調度規則是核心池大小,隊列大小,以及最大線程數和異常處理Handler來決定的。
3.? ? SERIAL_EXECUTOR本質是在THREAD_POOL_EXECUTOR的基礎上添加一個mTasks的集合來保證任務的順序執行。




總結

以上是默认站点為你收集整理的Android之AsyncTask两种线程池分析和总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得默认站点網站內容還不錯,歡迎將默认站点推薦給好友。