AsyncTask原理分析

線程池ThreadPoolExecutor
JDK5帶來(lái)的一大改進(jìn)就是Java的并發(fā)能力塘辅,它提供了三種并發(fā)武器:并發(fā)框架Executor月幌,并發(fā)集合類型如ConcurrentHashMap,并發(fā)控制類如CountDownLatch等野崇;圣經(jīng)《Effective Java》也說(shuō),盡量使用Exector而不是直接用Thread類進(jìn)行并發(fā)編程。
AsyncTask內(nèi)部也使用了線程池處理并發(fā)冒晰;線程池通過(guò)ThreadPoolExector
類構(gòu)造,這個(gè)構(gòu)造函數(shù)參數(shù)比較多竟块,它允許開(kāi)發(fā)者對(duì)線程池進(jìn)行定制壶运,我們先看看這每個(gè)參數(shù)是什么意思,然后看看Android是以何種方式定制的浪秘。
ThreadPoolExecutor的其他構(gòu)造函數(shù)最終都會(huì)調(diào)用如下的構(gòu)造函數(shù)完成對(duì)象創(chuàng)建工作:
1234567

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

corePoolSize: 核心線程數(shù)目蒋情,即使線程池沒(méi)有任務(wù)埠况,核心線程也不會(huì)終止(除非設(shè)置了allowCoreThreadTimeOut參數(shù))可以理解為“常駐線程”
maximumPoolSize: 線程池中允許的最大線程數(shù)目;一般來(lái)說(shuō)棵癣,線程越多辕翰,線程調(diào)度開(kāi)銷越大;因此一般都有這個(gè)限制狈谊。
keepAliveTime: 當(dāng)線程池中的線程數(shù)目比核心線程多的時(shí)候喜命,如果超過(guò)這個(gè)keepAliveTime的時(shí)間,多余的線程會(huì)被回收河劝;這些與核心線程相對(duì)的線程通常被稱為緩存線程
unit: keepAliveTime的時(shí)間單位
workQueue: 任務(wù)執(zhí)行前保存任務(wù)的隊(duì)列壁榕;這個(gè)隊(duì)列僅保存由execute提交的Runnable任務(wù)
threadFactory: 用來(lái)構(gòu)造線程池的工廠;一般都是使用默認(rèn)的赎瞎;
handler: 當(dāng)線程池由于線程數(shù)目和隊(duì)列限制而導(dǎo)致后續(xù)任務(wù)阻塞的時(shí)候牌里,線程池的處理方式。

那么务甥,當(dāng)一個(gè)新的任務(wù)到達(dá)的時(shí)候牡辽,線程池中的線程是如何調(diào)度的呢?(別慌敞临,講這么一大段線程池的知識(shí)态辛,是為了理解AsyncTask;Be Patient)
如果線程池中線程的數(shù)目少于corePoolSize挺尿,就算線程池中有其他的沒(méi)事做的核心線程因妙,線程池還是會(huì)重新創(chuàng)建一個(gè)核心線程;直到核心線程數(shù)目到達(dá)corePoolSize(常駐線程就位)
如果線程池中線程的數(shù)目大于或者等于corePoolSize票髓,但是工作隊(duì)列workQueue沒(méi)有滿,那么新的任務(wù)會(huì)放在隊(duì)列workQueue中铣耘,按照FIFO的原則依次等待執(zhí)行洽沟;(當(dāng)有核心線程處理完任務(wù)空閑出來(lái)后,會(huì)檢查這個(gè)工作隊(duì)列然后取出任務(wù)默默執(zhí)行去)
如果線程池中線程數(shù)目大于等于corePoolSize蜗细,并且工作隊(duì)列workQueue滿了裆操,但是總線程數(shù)目小于maximumPoolSize,那么直接創(chuàng)建一個(gè)線程處理被添加的任務(wù)炉媒。
如果工作隊(duì)列滿了踪区,并且線程池中線程的數(shù)目到達(dá)了最大數(shù)目maximumPoolSize,那么就會(huì)用最后一個(gè)構(gòu)造參數(shù)handler
處理吊骤;**默認(rèn)的處理方式是直接丟掉任務(wù)缎岗,然后拋出一個(gè)異常。

總結(jié)起來(lái)白粉,也即是說(shuō)传泊,當(dāng)有新的任務(wù)要處理時(shí)鼠渺,先看線程池中的線程數(shù)量是否大于 corePoolSize,再看緩沖隊(duì)列 workQueue 是否滿眷细,最后看線程池中的線程數(shù)量是否大于 maximumPoolSize拦盹。另外,當(dāng)線程池中的線程數(shù)量大于 corePoolSize 時(shí)溪椎,如果里面有線程的空閑時(shí)間超過(guò)了 keepAliveTime普舆,就將其移除線程池,這樣校读,可以動(dòng)態(tài)地調(diào)整線程池中線程的數(shù)量沼侣。

我們以API 22為例,看一看AsyncTask里面的線程池是以什么參數(shù)構(gòu)造的地熄;AsyncTask里面有“兩個(gè)”線程池华临;一個(gè)THREAD_POOL_EXECUTOR
一個(gè)SERIAL_EXECUTOR
;之所以打引號(hào)端考,是因?yàn)槠鋵?shí)SERIAL_EXECUTOR
也使用THREAD_POOL_EXECUTOR
實(shí)現(xiàn)的雅潭,只不過(guò)加了一個(gè)隊(duì)列弄成了串行而已,那么這個(gè)THREAD_POOL_EXECUTOR
是如何構(gòu)造的呢却特?
123456789

private static final int CORE_POOL_SIZE = CPU_COUNT + 1;private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;private static final int KEEP_ALIVE = 1;private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(128); public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

可以看到扶供,AsyncTask里面線程池是一個(gè)核心線程數(shù)為CPU + 1
,最大線程數(shù)為CPU * 2 + 1
裂明,工作隊(duì)列長(zhǎng)度為128的線程池椿浓;并且沒(méi)有傳遞handler
參數(shù),那么使用的就是默認(rèn)的Handler(拒絕執(zhí)行).
那么問(wèn)題來(lái)了:
如果任務(wù)過(guò)多闽晦,那么超過(guò)了工作隊(duì)列以及線程數(shù)目的限制導(dǎo)致這個(gè)線程池發(fā)生阻塞扳碍,那么悲劇發(fā)生,默認(rèn)的處理方式會(huì)直接拋出一個(gè)異常導(dǎo)致進(jìn)程掛掉仙蛉。假設(shè)你自己寫(xiě)一個(gè)異步圖片加載的框架笋敞,然后用AsyncTask實(shí)現(xiàn)的話,當(dāng)你快速滑動(dòng)ListView的時(shí)候很容易發(fā)生這種異常荠瘪;這也是為什么各大ImageLoader都是自己寫(xiě)線程池和Handlder的原因夯巷。

這個(gè)線程池是一個(gè)靜態(tài)變量;那么在同一個(gè)進(jìn)程之內(nèi)哀墓,所有地方使用到的AsyncTask默認(rèn)構(gòu)造函數(shù)構(gòu)造出來(lái)的AsyncTask都使用的是同一個(gè)線程池趁餐,如果App模塊比較多并且不加控制的話,很容易滿足第一條的崩潰條件篮绰;如果你不幸在不同的AsyncTask的doInBackgroud里面訪問(wèn)了共享資源后雷,那么就會(huì)發(fā)生各種并發(fā)編程問(wèn)題。

在AsyncTask全部執(zhí)行完畢之后,進(jìn)程中還是會(huì)常駐corePoolSize個(gè)線程喷面;在Android 4.4 (API 19)以下星瘾,這個(gè)corePoolSize是hardcode的,數(shù)值是5惧辈;API 19改成了cpu + 1
琳状;也就是說(shuō),在Android 4.4以前盒齿;如果你執(zhí)行了超過(guò)五個(gè)AsyncTask念逞;然后啥也不干了,進(jìn)程中還是會(huì)有5個(gè)AsyncTask線程边翁;不信翎承,你看:


Handler
AsyncTask里面的handler很簡(jiǎn)單,如下(API 22代碼):
12345

private static final InternalHandler sHandler = new InternalHandler();public InternalHandler() { super(Looper.getMainLooper());}

注意符匾,這里直接用的主線程的Looper叨咖;如果去看API 22以下的代碼,會(huì)發(fā)現(xiàn)它沒(méi)有這個(gè)構(gòu)造函數(shù)啊胶,而是使用默認(rèn)的甸各;默認(rèn)情況下,Handler會(huì)使用當(dāng)前線程的Looper焰坪,如果你的AsyncTask是在子線程創(chuàng)建的趣倾,那么很不幸,你的onPreExecute
和onPostExecute
并非在UI線程執(zhí)行某饰,而是被Handler post到創(chuàng)建它的那個(gè)線程執(zhí)行儒恋;如果你在這兩個(gè)線程更新了UI,那么直接導(dǎo)致崩潰黔漂。這也是大家口口相傳的AsyncTask必須在主線程創(chuàng)建的原因诫尽。
另外,AsyncTask里面的這個(gè)Handler是一個(gè)靜態(tài)變量炬守,也就是說(shuō)它是在類加載的時(shí)候創(chuàng)建的箱锐;如果在你的APP進(jìn)程里面,以前從來(lái)沒(méi)有使用過(guò)AsyncTask劳较,然后在子線程使用AsyncTask的相關(guān)變量,那么導(dǎo)致靜態(tài)Handler初始化浩聋,如果在API 16以下观蜗,那么會(huì)出現(xiàn)上面同樣的問(wèn)題;這就是AsyncTask必須在主線程初始化 的原因衣洁。
事實(shí)上墓捻,在Android 4.1(API 16)以后,在APP主線程ActivityThread的main函數(shù)里面,直接調(diào)用了AscynTask.init
函數(shù)確保這個(gè)類是在主線程初始化的砖第;另外撤卢,init這個(gè)函數(shù)里面獲取了InternalHandler
的Looper,由于是在主線程執(zhí)行的梧兼,因此放吩,AsyncTask的Handler用的也是主線程的Looper。這個(gè)問(wèn)題從而得到徹底的解決羽杰。
AsyncTask是并行執(zhí)行的嗎渡紫?
現(xiàn)在知道AsyncTask內(nèi)部有一個(gè)線程池,那么派發(fā)給AsyncTask的任務(wù)是并行執(zhí)行的嗎考赛?
答案是不確定惕澎。在Android 1.5剛引入的時(shí)候,AsyncTask的execute
是串行執(zhí)行的颜骤;到了Android 1.6直到Android 2.3.2唧喉,又被修改為并行執(zhí)行了,這個(gè)執(zhí)行任務(wù)的線程池就是THREAD_POOL_EXECUTOR
忍抽,因此在一個(gè)進(jìn)程內(nèi)八孝,所有的AsyncTask都是并行執(zhí)行的;但是在Android 3.0以后梯找,如果你使用execute
函數(shù)直接執(zhí)行AsyncTask唆阿,那么這些任務(wù)是串行執(zhí)行的;(你說(shuō)蛋疼不)源代碼如下:
123

public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);}

這個(gè)sDefaultExecutor
就是用來(lái)執(zhí)行任務(wù)的線程池锈锤,那么它的值是什么呢驯鳖?繼續(xù)看代碼:
1

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

因此結(jié)論就來(lái)了:Android 3.0以上,AsyncTask默認(rèn)并不是并行執(zhí)行的久免;
為什么默認(rèn)不并行執(zhí)行浅辙?
也許你不理解,為什么AsyncTask默認(rèn)把它設(shè)計(jì)為串行執(zhí)行的呢阎姥?
由于一個(gè)進(jìn)程內(nèi)所有的AsyncTask都是使用的同一個(gè)線程池執(zhí)行任務(wù)记舆;如果同時(shí)有幾個(gè)AsyncTask一起并行執(zhí)行的話,恰好AysncTask的使用者在doInbackgroud
里面訪問(wèn)了相同的資源呼巴,但是自己沒(méi)有處理同步問(wèn)題泽腮;那么就有可能導(dǎo)致災(zāi)難性的后果!
由于開(kāi)發(fā)者通常不會(huì)意識(shí)到需要對(duì)他們創(chuàng)建的所有的AsyncTask對(duì)象里面的doInbackgroud
做同步處理衣赶,因此诊赊,API的設(shè)計(jì)者為了避免這種無(wú)意中訪問(wèn)并發(fā)資源的問(wèn)題,干脆把這個(gè)API設(shè)置為默認(rèn)所有串行執(zhí)行的了府瞄。如果你明確知道自己需要并行處理任務(wù)碧磅,那么你需要使用executeOnExecutor(Executor exec,Params... params)
這個(gè)函數(shù)來(lái)指定你用來(lái)執(zhí)行任務(wù)的線程池,同時(shí)為自己的行為負(fù)責(zé)。(處理同步問(wèn)題)
實(shí)際上《Effective Java》里面有一條原則說(shuō)的就是這種情況:不要在同步塊里面調(diào)用不可信的外來(lái)函數(shù)鲸郊。這里明顯違背了這個(gè)原則:AsyncTask這個(gè)類并不知道使用者會(huì)在doInBackgroud
這個(gè)函數(shù)里面做什么丰榴,但是對(duì)它的行為做了某種假設(shè)。
如何讓AsyncTask并行執(zhí)行秆撮?
正如上面所說(shuō)四濒,如果你確定自己做好了同步處理,或者你沒(méi)有在不同的AsyncTask里面訪問(wèn)共享資源像吻,需要AsyncTask能夠并行處理任務(wù)的話峻黍,你可以用帶有兩個(gè)參數(shù)的executeOnExecutor
執(zhí)行任務(wù):
1234567

new AsyncTask<Void, Void, Vo @Override protected Void doInBackground(Void... params) { // do something return null; }}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

更好的AsyncTask
從上面的分析得知,AsyncTask有如下問(wèn)題:
默認(rèn)的AsyncTask如果處理的任務(wù)過(guò)多拨匆,會(huì)導(dǎo)致程序直接崩潰姆涩;
AsyncTask類必須在主線程初始化,必須在主線程創(chuàng)建惭每,不然在API 16以下很大概率崩潰骨饿。
如果你曾經(jīng)使用過(guò)AsyncTask,以后不用了台腥;在Android 4.4以下宏赘,進(jìn)程內(nèi)也默認(rèn)有5個(gè)AsyncTask線程;在Android 4.4以上黎侈,默認(rèn)有CPU + 1
個(gè)線程察署。
Android 3.0以上的AsyncTask默認(rèn)是串行執(zhí)行任務(wù)的;如果要并行執(zhí)行需要調(diào)用低版本沒(méi)有的API峻汉,處理麻煩贴汪。

因此我們對(duì)系統(tǒng)的AsyncTask做了一些修改,在不同Android版本提供一致的行為休吠,并且提高了使用此類的安全性扳埂,主要改動(dòng)如下:
添加對(duì)于任務(wù)過(guò)多導(dǎo)致崩潰的異常保護(hù);在這里進(jìn)行必要的數(shù)據(jù)統(tǒng)計(jì)上報(bào)工作瘤礁;如果出現(xiàn)這個(gè)問(wèn)題阳懂,說(shuō)明AsyncTask不適合這種場(chǎng)景了,需要考慮重構(gòu)柜思;
移植API 22對(duì)于Handler的處理岩调;這樣就算在線程創(chuàng)建異步任務(wù),也不會(huì)有任何問(wèn)題赡盘;
提供串行執(zhí)行和并行執(zhí)行的execute
方法誊辉;默認(rèn)串行執(zhí)行,如果明確知道自己在干什么亡脑,可以使用executeParallel
并行執(zhí)行。
在doInbackgroud
里面頻繁崩潰的地方加上try..catch
;自己處理數(shù)據(jù)上報(bào)工作霉咨。

完整代碼見(jiàn)gist蛙紫,BetterAsyncTask
原文地址:http://weishu.me/2016/01/18/dive-into-asynctask/


大體流程

? excute()方法中首先直接調(diào)用preExcute()方法
? AsyncTask的構(gòu)造方法構(gòu)造了mWorkder這個(gè)WorkerRunnable對(duì)象.再用mWorker構(gòu)造一個(gè)FutureTask對(duì)象丟到線程池里面去執(zhí)行
? AsyncTask的成員變量有個(gè)InternalHandler,構(gòu)造的時(shí)候進(jìn)行初始化.
? FutureTask轉(zhuǎn)調(diào)mWorker的run方法最后在線程池的子線程調(diào)用doInBackGround()方法.
? 然后FutureTask調(diào)用setResult()方法把運(yùn)行結(jié)果返回,完成后調(diào)用FutureTask的done方法.這里面用InternalHandler發(fā)了個(gè)消息給主線程,最后拿到結(jié)果調(diào)用 finish()

  • FutureTask類
    它需要Callable接口類型的參數(shù),在AsyncTask類中途戒,創(chuàng)建了WorkerRunnable的實(shí)現(xiàn)類和FutureTask類坑傅,在run方法中調(diào)用
private static abstract class WorkerRunnable<Params, Result> 
                                implements Callable<Result> {
    Params[] mParams;
}
    
    
    
public AsyncTask() {
   mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            //調(diào)用熟悉的doInBackground方法,在子線程中執(zhí)行喷斋,
            return postResult(doInBackground(mParams));
        }
    };

    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 occured 
while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

//執(zhí)行execute方法時(shí)
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    onPreExecute();
    mWorker.mParams = params;
    //將任務(wù)添加到Executor的實(shí)現(xiàn)類ThreadPoolExecutor里面
    exec.execute(mFuture);
}
//FutureTask任務(wù)
public class FutureTask<V> implements RunnableFuture<V>{
    private volatile int state;//任務(wù)運(yùn)行的狀態(tài)
    //構(gòu)造函數(shù)java.util.concurrent.Callable
    public FutureTask(Callable<V> callable) {
        
    }

    //取消任務(wù)通過(guò)線程執(zhí)行interrupt

    public boolean cancel(boolean mayInterruptIfRunning) {
         try {
            Thread t = runner;
            if (t != null)
                t.interrupt();
        } finally { // final state
            UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
        }

    }
    
    //此方法調(diào)用awaitDone唁毒,它會(huì)阻塞線程,一直等到線程執(zhí)行完成
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
    
    //變量c就是構(gòu)造函數(shù)傳的Callable<V> callable對(duì)象
    public void run() {
       if (c != null && state == NEW) {
            V result;
            result = c.call();
            //call里面的任務(wù)執(zhí)行完畢之后星爪,在set方法里面調(diào)用finishCompletion方法浆西,
              之后調(diào)用done方法表示任務(wù)執(zhí)行完成。
            set(result);
        }
    }
    
    //消除和信號(hào)顽腾,所有等待的線程近零,調(diào)用done()
    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        done();
        callable = null;        // to reduce footprint
    }
    
    //異步任務(wù)執(zhí)行完成拔妥,回調(diào)
    protected void done() { 
    
    }
}

ThreadPoolExecutor

任務(wù)執(zhí)行在這個(gè)類里面用到了ReentrantLock鎖顾孽,實(shí)現(xiàn)了ExecutorService接口。

//addWorker方法第二個(gè)參數(shù)core含義:true表示核心線程5蝴猪,false表示非核心線程128
public void execute(Runnable command) {
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    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);
    }
    else if (!addWorker(command, false))
        //調(diào)用handler.rejectedExecution拋出異常
        reject(command);
}

 private boolean addWorker(Runnable firstTask, boolean core) {
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        for (;;) {
            int wc = workerCountOf(c);//當(dāng)前work線程數(shù)量
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
        }
    }

    Worker w = new Worker(firstTask);
    Thread t = w.thread;

    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        workers.add(w);
    } finally {
        mainLock.unlock();
    }

    t.start();
    return true;
}

InternalHandler

任務(wù)執(zhí)行完時(shí)在子線程漓摩,此時(shí)會(huì)發(fā)送一個(gè)handler消息裙士,handler接收到這個(gè)消息就會(huì)調(diào)用AsyncTask的finish方法,接著調(diào)用onPostExecute管毙。

private void finish(Result result) {
    if (isCancelled()) {
        onCancelled(result);
    } else {
        onPostExecute(result);
    }
    mStatus = Status.FINISHED;
}

private static class InternalHandler extends Handler {
    public void handleMessage(Message msg) {
        AsyncTaskResult result = (AsyncTaskResult) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

異步任務(wù)執(zhí)行的結(jié)果腿椎,主線程無(wú)法輕易的獲取

Java FutureTask 異步任務(wù)操作提供了便利性

1.獲取異步任務(wù)的返回值
2.監(jiān)聽(tīng)異步任務(wù)的執(zhí)行完畢
3.取消異步任務(wù)

doBackground(call)
call的返回值在Future的done方法中獲取

->onPostExecute

new MyTask().execute();

實(shí)例化:
new AsyncTask() -> new FutureTask()

執(zhí)行:
Executor.execute(mFuture) -> SerialExecutor.myTasks(隊(duì)列)
-> (線程池)THREAD_POOL_EXECUTOR.execute

線程池中的所有線程,為了執(zhí)行異步任務(wù)

CORE_POOL_SIZE 核心線程數(shù)
MAXIMUM_POOL_SIZE 最大線程數(shù)量
KEEP_ALIVE 1s閑置回收
TimeUnit.SECONDS 時(shí)間單位
sPoolWorkQueue 異步任務(wù)隊(duì)列
sThreadFactory 線程工廠


如果當(dāng)前線程池中的數(shù)量小于corePoolSize锅风,創(chuàng)建并添加的任務(wù)酥诽。
如果當(dāng)前線程池中的數(shù)量等于corePoolSize,緩沖隊(duì)列 workQueue未滿皱埠,那么任務(wù)被放入緩沖隊(duì)列肮帐、等待任務(wù)調(diào)度執(zhí)行。
如果當(dāng)前線程池中的數(shù)量大于corePoolSize边器,緩沖隊(duì)列workQueue已滿训枢,并且線程池中的數(shù)量小于maximumPoolSize,新提交任務(wù)會(huì)創(chuàng)建新線程執(zhí)行任務(wù)忘巧。
如果當(dāng)前線程池中的數(shù)量大于corePoolSize恒界,緩沖隊(duì)列workQueue已滿,并且線程池中的數(shù)量等于maximumPoolSize砚嘴,新提交任務(wù)由Handler處理十酣。
當(dāng)線程池中的線程大于corePoolSize時(shí)涩拙,多余線程空閑時(shí)間超過(guò)keepAliveTime時(shí),會(huì)關(guān)閉這部分線程耸采。

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

1.線程池容量不夠拋出異常
2.內(nèi)存泄露
3.一個(gè)線程兴泥,一個(gè)異步任務(wù)(?)

測(cè)試代碼

public class FutureTest1 {

    public static void main(String[] args) {
        System.out.println("main ID: " + Thread.currentThread().getId());
        Task work = new Task();
        FutureTask<Integer> future = new FutureTask<Integer>(work) {
            // 異步任務(wù)執(zhí)行完成虾宇,回調(diào)
            @Override
            protected void done() {
                try {
                    System.out.println("done:" + get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

        };
        // 線程池(使用了預(yù)定義的配置)
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(future);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        // 取消異步任務(wù)
        // future.cancel(true);

        try {
            // 阻塞搓彻,等待異步任務(wù)執(zhí)行完畢
            System.out.println(future.get()); // 獲取異步任務(wù)的返回值
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    // 異步任務(wù)
    static class Task implements Callable<Integer> {

        // 返回異步任務(wù)的執(zhí)行結(jié)果
        @Override
        public Integer call() throws Exception {
            int i = 0;
            for (; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + "_"
                            + i);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("ID: " + Thread.currentThread().getId());

            return i;
        }

    }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市嘱朽,隨后出現(xiàn)的幾起案子旭贬,更是在濱河造成了極大的恐慌,老刑警劉巖搪泳,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稀轨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡森书,警方通過(guò)查閱死者的電腦和手機(jī)靶端,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凛膏,“玉大人杨名,你說(shuō)我怎么就攤上這事〔粒” “怎么了台谍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吁断。 經(jīng)常有香客問(wèn)我趁蕊,道長(zhǎng),這世上最難降的妖魔是什么仔役? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任掷伙,我火速辦了婚禮,結(jié)果婚禮上又兵,老公的妹妹穿的比我還像新娘任柜。我一直安慰自己,他們只是感情好沛厨,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布宙地。 她就那樣靜靜地躺著,像睡著了一般逆皮。 火紅的嫁衣襯著肌膚如雪宅粥。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,793評(píng)論 1 314
  • 那天电谣,我揣著相機(jī)與錄音秽梅,去河邊找鬼抹蚀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛企垦,可吹牛的內(nèi)容都是我干的况鸣。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼竹观,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了潜索?” 一聲冷哼從身側(cè)響起臭增,我...
    開(kāi)封第一講書(shū)人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竹习,沒(méi)想到半個(gè)月后誊抛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡整陌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年拗窃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泌辫。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡随夸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出震放,到底是詐尸還是另有隱情宾毒,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布殿遂,位于F島的核電站诈铛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏墨礁。R本人自食惡果不足惜幢竹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恩静。 院中可真熱鬧焕毫,春花似錦、人聲如沸蜕企。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)轻掩。三九已至幸乒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唇牧,已是汗流浹背罕扎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工聚唐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腔召。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓杆查,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親臀蛛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子亲桦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

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

  • Android Handler機(jī)制系列文章整體內(nèi)容如下: Android Handler機(jī)制1之ThreadAnd...
    隔壁老李頭閱讀 3,219評(píng)論 1 15
  • AsyncTask在安卓中常用于線程間通信。在子線程執(zhí)行耗時(shí)任務(wù)浊仆,在主線程更新UI客峭。 AsyncTask內(nèi)部封裝了...
    著名的閱讀 205評(píng)論 0 3
  • Android中的線程 線程,在Android中是非常重要的抡柿,主線程處理UI界面舔琅,子線程處理耗時(shí)操作。如果在主線程...
    shenhuniurou閱讀 757評(píng)論 0 3
  • 雖說(shuō)現(xiàn)在做網(wǎng)絡(luò)請(qǐng)求有了Volley全家桶和OkHttp這樣好用的庫(kù),但是在處理其他后臺(tái)任務(wù)以及與UI交互上囱稽,還是需...
    weishu閱讀 3,379評(píng)論 10 55
  • 題目描述輸入某二叉樹(shù)的前序遍歷和中序遍歷的結(jié)果郊尝,請(qǐng)重建出該二叉樹(shù)。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復(fù)的...
    Hathaway_桉閱讀 113評(píng)論 0 0