AsyncTask原理分析

線程池ThreadPoolExecutor
JDK5帶來的一大改進(jìn)就是Java的并發(fā)能力,它提供了三種并發(fā)武器:并發(fā)框架Executor,并發(fā)集合類型如ConcurrentHashMap,并發(fā)控制類如CountDownLatch等;圣經(jīng)《Effective Java》也說,盡量使用Exector而不是直接用Thread類進(jìn)行并發(fā)編程。
AsyncTask內(nèi)部也使用了線程池處理并發(fā);線程池通過ThreadPoolExector
類構(gòu)造,這個(gè)構(gòu)造函數(shù)參數(shù)比較多,它允許開發(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ù)目,即使線程池沒有任務(wù),核心線程也不會(huì)終止(除非設(shè)置了allowCoreThreadTimeOut參數(shù))可以理解為“常駐線程”
maximumPoolSize: 線程池中允許的最大線程數(shù)目;一般來說,線程越多,線程調(diào)度開銷越大;因此一般都有這個(gè)限制。
keepAliveTime: 當(dāng)線程池中的線程數(shù)目比核心線程多的時(shí)候,如果超過這個(gè)keepAliveTime的時(shí)間,多余的線程會(huì)被回收;這些與核心線程相對(duì)的線程通常被稱為緩存線程
unit: keepAliveTime的時(shí)間單位
workQueue: 任務(wù)執(zhí)行前保存任務(wù)的隊(duì)列;這個(gè)隊(duì)列僅保存由execute提交的Runnable任務(wù)
threadFactory: 用來構(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,就算線程池中有其他的沒事做的核心線程,線程池還是會(huì)重新創(chuàng)建一個(gè)核心線程;直到核心線程數(shù)目到達(dá)corePoolSize(常駐線程就位)
如果線程池中線程的數(shù)目大于或者等于corePoolSize,但是工作隊(duì)列workQueue沒有滿,那么新的任務(wù)會(huì)放在隊(duì)列workQueue中,按照FIFO的原則依次等待執(zhí)行;(當(dāng)有核心線程處理完任務(wù)空閑出來后,會(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é)起來,也即是說,當(dāng)有新的任務(wù)要處理時(shí),先看線程池中的線程數(shù)量是否大于 corePoolSize,再看緩沖隊(duì)列 workQueue 是否滿,最后看線程池中的線程數(shù)量是否大于 maximumPoolSize。另外,當(dāng)線程池中的線程數(shù)量大于 corePoolSize 時(shí),如果里面有線程的空閑時(shí)間超過了 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)的,只不過加了一個(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ì)列長度為128的線程池;并且沒有傳遞handler
參數(shù),那么使用的就是默認(rèn)的Handler(拒絕執(zhí)行).
那么問題來了:
如果任務(wù)過多,那么超過了工作隊(duì)列以及線程數(shù)目的限制導(dǎo)致這個(gè)線程池發(fā)生阻塞,那么悲劇發(fā)生,默認(rèn)的處理方式會(huì)直接拋出一個(gè)異常導(dǎo)致進(jìn)程掛掉。假設(shè)你自己寫一個(gè)異步圖片加載的框架,然后用AsyncTask實(shí)現(xiàn)的話,當(dāng)你快速滑動(dòng)ListView的時(shí)候很容易發(fā)生這種異常;這也是為什么各大ImageLoader都是自己寫線程池和Handlder的原因。

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

在AsyncTask全部執(zhí)行完畢之后,進(jìn)程中還是會(huì)常駐corePoolSize個(gè)線程;在Android 4.4 (API 19)以下,這個(gè)corePoolSize是hardcode的,數(shù)值是5;API 19改成了cpu + 1
;也就是說,在Android 4.4以前;如果你執(zhí)行了超過五個(gè)AsyncTask;然后啥也不干了,進(jìn)程中還是會(huì)有5個(gè)AsyncTask線程;不信,你看:


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

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

注意,這里直接用的主線程的Looper;如果去看API 22以下的代碼,會(huì)發(fā)現(xiàn)它沒有這個(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)變量,也就是說它是在類加載的時(shí)候創(chuàng)建的;如果在你的APP進(jìn)程里面,以前從來沒有使用過AsyncTask,然后在子線程使用AsyncTask的相關(guān)變量,那么導(dǎo)致靜態(tài)Handler初始化,如果在API 16以下,那么會(huì)出現(xià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è)問題從而得到徹底的解決。
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í)行的;(你說蛋疼不)源代碼如下:
123

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

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

private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

因此結(jié)論就來了: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
里面訪問了相同的資源,但是自己沒有處理同步問題;那么就有可能導(dǎo)致災(zāi)難性的后果!
由于開發(fā)者通常不會(huì)意識(shí)到需要對(duì)他們創(chuàng)建的所有的AsyncTask對(duì)象里面的doInbackgroud
做同步處理,因此,API的設(shè)計(jì)者為了避免這種無意中訪問并發(fā)資源的問題,干脆把這個(gè)API設(shè)置為默認(rèn)所有串行執(zhí)行的了。如果你明確知道自己需要并行處理任務(wù),那么你需要使用executeOnExecutor(Executor exec,Params... params)
這個(gè)函數(shù)來指定你用來執(zhí)行任務(wù)的線程池,同時(shí)為自己的行為負(fù)責(zé)。(處理同步問題)
實(shí)際上《Effective Java》里面有一條原則說的就是這種情況:不要在同步塊里面調(diào)用不可信的外來函數(shù)。這里明顯違背了這個(gè)原則:AsyncTask這個(gè)類并不知道使用者會(huì)在doInBackgroud
這個(gè)函數(shù)里面做什么,但是對(duì)它的行為做了某種假設(shè)。
如何讓AsyncTask并行執(zhí)行?
正如上面所說,如果你確定自己做好了同步處理,或者你沒有在不同的AsyncTask里面訪問共享資源,需要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有如下問題:
默認(rèn)的AsyncTask如果處理的任務(wù)過多,會(huì)導(dǎo)致程序直接崩潰;
AsyncTask類必須在主線程初始化,必須在主線程創(chuàng)建,不然在API 16以下很大概率崩潰。
如果你曾經(jīng)使用過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)用低版本沒有的API,處理麻煩。

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

完整代碼見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ù)通過線程執(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é)果,主線程無法輕易的獲取

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

1.獲取異步任務(wù)的返回值
2.監(jiān)聽異步任務(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í)間超過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ù)(?)

測試代碼

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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容