Android的線程和線程池

除了Thread外,在Android中扮演線程的角色還有很多,比如AsyncTask和IntentService,同時(shí)HandlerThread也是一種特殊的線程肄满。
盡管AsyncTask和IntentService以及HandlerThread的表現(xiàn)形式有區(qū)別于傳統(tǒng)的線程,但是本質(zhì)上仍然是傳統(tǒng)的線程质涛。

AsyncTask

AsyncTask是一種輕量級(jí)的異步任務(wù)類稠歉,它可以在線程池中執(zhí)行后臺(tái)任務(wù),并把執(zhí)行進(jìn)度和最終結(jié)果傳遞到主線程并在主線程中更新UI汇陆。
AsyncTask封裝了Thread和Handler怒炸。
AsyncTask并不適合特別耗時(shí)的后臺(tái)任務(wù),對(duì)于特別耗時(shí)的后臺(tái)任務(wù)毡代,建議交給線程池阅羹。

  • AsyncTask的類聲明
/**
*@Params 參數(shù)類型
*@Progress 后臺(tái)任務(wù)的執(zhí)行進(jìn)度類型
*@Result 后臺(tái)任務(wù)的返回結(jié)果的類型
public abstract class AsyncTask<Params,Progress,Result>

AsyncTask提供了4個(gè)核心方法,他們的含義如下:

  • onPreExecute() 在主線程中執(zhí)行教寂,在異步任務(wù)執(zhí)行前被調(diào)用捏鱼,一般可以用于做一些準(zhǔn)備工作。
  • doInBackground(Params...params) 在線程池中執(zhí)行酪耕,此方法用于執(zhí)行異步任務(wù) 导梆,params參數(shù)表示異步任務(wù)輸入的參數(shù)。在此方法中可以通過publicProgress方法來更新任務(wù)的進(jìn)度迂烁,publicProgress方法會(huì)調(diào)用onPublicUpdate方法卫键。另外此方法需要返回計(jì)算機(jī)過給onPostExecute方法。
  • onProgressUpdate(Progress...values)在主線程中執(zhí)行辅甥,當(dāng)后臺(tái)任務(wù)的執(zhí)行進(jìn)度放生改變時(shí)被調(diào)用洗做。
  • onPostExecute(Result...result)在主線程中執(zhí)行,在異步任務(wù)執(zhí)行之后址芯,此方法會(huì)被調(diào)用灾茁,其中result是后臺(tái)任務(wù)被取消時(shí)調(diào)用。這個(gè)時(shí)候onPostExecute()不會(huì)被調(diào)用

除了上述的四個(gè)方法外谷炸,AsyncTask還提供onCancelled()方法北专,它同樣在主線程中執(zhí)行,當(dāng)異步任務(wù)被取消時(shí)調(diào)用旬陡。這個(gè)時(shí)候onPostExecute()不會(huì)被調(diào)用拓颓。

  • 示例
private class DownloadFilesTask extends AsyncTask<URL,Interger,Long>{

    protected Long doInBackground(URL...urls){
        int count = urls.length;
        long totalSize = 0;
        for (int i=0;i<count;i++){
            totalSize += DownLoader.downloadFile(urls[i]);
            publishProgress((int)(i/(float)count*100));
            // Escape early if cancel() is called
            if (isCancelled()){
                break;
            }
        }
        return totalSize;
    }

    protected void onProgressUpdate(Interger... progress){
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result){
        showDialog("Download"+result+"bytes");
    }
}
  • 使用限制
  1. AsyncTask的類必須在主線程中加載。
  2. AsyncTask的對(duì)象必須在主線程中加載描孟。
  3. execute必須在UI線程中調(diào)用驶睦。
  4. 不要在程序中直接調(diào)用onPreExecute()砰左,onPostExecute,doInBackground()和onProgressUpdate方法场航。
  5. 一個(gè)AsyncTask對(duì)象只能執(zhí)行一次缠导,即只能調(diào)用一次execute方法,否則回報(bào)異常溉痢。
  6. 從Android3.0開始僻造,為避免AsyncTask所帶來的并發(fā)錯(cuò)誤,AsyncTask又采用一個(gè)線程來執(zhí)行任務(wù)孩饼。盡管如此髓削,Android3.0的后續(xù)版本,我們?nèi)钥梢酝ㄟ^AsyncTask的executeOnExecutor方法來并行執(zhí)行任務(wù)镀娶。

AsyncTask的工作原理

  • execute方法
public final AsyncTask<Params,Progress,Result> execute(Params... params){
    return executeExecutor(sDefaultExecutor,params);
}

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;
    onPreExecute();
    mWorker.mParams = params;
    exec.execute(mFuture);
    return this;
}

sDefaultExecutor實(shí)際是一個(gè)串行的線程池立膛,一個(gè)進(jìn)程中所有的AsyncTask全部在這個(gè)串行的線程池中執(zhí)行。

  • 線程池執(zhí)行
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

private static class SerialExecutor implements Executor{
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
    Runnable mActive;

    public synchroized void execute (final Runnable r){
        mTasks.offer(new Runnable(){
            public void run(){
                try{
                    r.run();
                }finally{
                    scheduleNext();
                }
            }
        });
        if(mActive==null){
            scheduleNext();
        }
    }

    protected synchroized void scheduleNext(){
        if((mActive==mTasks.poll())!=null){
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}

首先系統(tǒng)會(huì)把AsyncTask的Params參數(shù)封裝FutureTask對(duì)象汽畴,F(xiàn)utureTask是一個(gè)并發(fā)類旧巾,在這個(gè)它充當(dāng)Runnable的作用。
接著FutureTask會(huì)交給SerialExecutor的execute去處理忍些,SerialExecutor的execute方法首先會(huì)把FutureTask對(duì)象插入到任務(wù)隊(duì)列mTasks中鲁猩,如果這時(shí)候沒有正在活動(dòng)的AsyncTask任務(wù),那么就會(huì)調(diào)用SerialExcutor的scheduleNext方法來執(zhí)行下一個(gè)AsyncTask任務(wù)罢坝。
同時(shí)當(dāng)一個(gè)AsyncTask執(zhí)行完之后廓握,AsyncTask會(huì)繼續(xù)執(zhí)行其他任務(wù)直到所有任務(wù)都被執(zhí)行為止,從這一點(diǎn)可以看出嘁酿,默認(rèn)情況下AsyncTask是串行執(zhí)行隙券。

AsyncTask有兩個(gè)線程池(SerialExcutor和THREAD_POOL_EXECUTOR)和一個(gè)Handler(IntentHandler)

SerialExecutor用于任務(wù)排隊(duì),THREAD_POOL_EXECUTOR
用于真正的執(zhí)行任務(wù)闹司。
IntentHandler用于將執(zhí)行環(huán)境從線程池切換到主線程娱仔。

AsyncTask的構(gòu)造方法中如下一段代碼,由于FutureTask的run方法會(huì)調(diào)用mWorker的call方法游桩,因此mWorker的call方法最終會(huì)在線程池中執(zhí)行牲迫。

mWorker = new WorkerRunnable<Params,Result>(){
    public Result call() throws Exception{
        mTaskInvoked.set(true);

        Process.setThreadPriority(Progress.THREAD_PRIORITY_BACKGROUND);
        // noinspection unchecked
        return postResult(doInBackground(mParams));
    }
};

在mWorker的call方法中,首先將mTaskInvoked設(shè)為true借卧,表示當(dāng)前任務(wù)已經(jīng)被調(diào)用過了盹憎,然后執(zhí)行AsyncTask的doInBackground方法,接著將其返回值傳遞給postResult方法铐刘。

private Result postResult(Result result){
    @SuppressWarnings("unchecked)
    Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this,result));
    message.sendToTarget();
    return result;
}

postResult方法會(huì)通過sHandler發(fā)送一個(gè)MESSAGE_POST_RESULT的消息陪每,這個(gè)sHandler定義如下:

private static final InternalHandler sHandler = new InternalHandler();

private static class InteralHandler extends Handler{
    @SuppressWarnings({"unchecked","RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg){
        AsyncTaskResult result = (AsyncTaskResult)msg.obj;
        switch(msg.what){
            case MESSAGE_POST_RESULT:
                //Thread is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

sHandler會(huì)一個(gè)靜態(tài)的Handler對(duì)象,為了能夠?qū)?zhí)行環(huán)境切換到主線程,這就要求sHandler這個(gè)對(duì)象必須在主線程中創(chuàng)建檩禾。由于靜態(tài)成員會(huì)在加載類的時(shí)候進(jìn)行初始化挂签,因此變相要求AsyncTask的類必須在主線程中加載,否則同一線程中的AsyncTask都無法工作盼产。sHandler收到MESSAGE_POST_RESULT這個(gè)消息后回調(diào)AsyncTask的finish方法竹握。

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

如果AsyncTask被取消了被調(diào)用onCancelled方法,否則就調(diào)用onPostExecute方法辆飘,可以看出doInBackground中的result會(huì)傳遞給onPostExecute方法。

如果要并行執(zhí)行谓传,要使用executeOnExcutor方法蜈项。

HandlerThread

HandlerThread繼承了Thread,是一種可以使用Handler的Thread续挟,它的實(shí)現(xiàn)也很簡單紧卒,就是在run方法中通過Looper.prepare
創(chuàng)建消息隊(duì)列,并通過Looper.loop來開啟消息循環(huán)诗祸,這樣在實(shí)際中就允許在HandlerThread中創(chuàng)建Handler了跑芳,HandlerThread的run方法如下所示:

public void run(){
    mTid = Progress.myTid();
    Looper.prepare();
    synchroized(this){
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Progress.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

HnadlerThread在內(nèi)部創(chuàng)建了一個(gè)消息隊(duì)列,外部需要通過Handler的消息方式來通知HandlerThread執(zhí)行一個(gè)具體任務(wù)直颅。

HandlerThread的run是一個(gè)無限循環(huán)博个,因此當(dāng)明確不需要時(shí)通過它的quit或者quitSafely方法終止線程運(yùn)行。
一個(gè)具體的應(yīng)用場景就是IntentService功偿。

IntentService

IntentService是一種特殊的Service盆佣,它繼承Service并且它是一個(gè)抽象類,因此創(chuàng)建它的子類才能使用IntentService械荷。
IntentService可用于執(zhí)行后臺(tái)耗時(shí)任務(wù)共耍,當(dāng)任務(wù)執(zhí)行后它會(huì)自動(dòng)停止,同時(shí)由于IntentService是服務(wù)的原因吨瞎,導(dǎo)致它的優(yōu)先級(jí)比單純的線程要高很多痹兜,所以IntentService適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)。
IntentService封裝了HandlerThread和Handler颤诀。

  • onCreate
public void onCreate(){
    
    super.onCreate();
    HandlerThread thread = new HandlerThread("IntentService["+mName+"]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceHandler);
}

當(dāng)IntentService被第一次啟動(dòng)時(shí)字旭,它的onCreate方法會(huì)被調(diào)用,onCreate方法會(huì)創(chuàng)建一個(gè)HandlerThread着绊,然后使用它的Looper來構(gòu)造一個(gè)Handler對(duì)象mServiceHandler谐算,這樣通過mServiceHandler發(fā)送的消息都會(huì)在HandlerThread中執(zhí)行,從這個(gè)角度看归露, IntentService也可以用于執(zhí)行后臺(tái)任務(wù)洲脂。每次啟動(dòng)IntentService,它的onStartCommand方法就會(huì)調(diào)用一次。IntentService在onStartCommand中處理每個(gè)任務(wù)的Intent恐锦。onStartCommand方法中調(diào)用start方法處理Intent往果。

  • onStartCommand的start方法
public void onStart(Intent intent, int startId){
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

IntentService僅僅是用過mServiceHandler發(fā)送一個(gè)消息,這個(gè)消息會(huì)在HandlerThread中處理一铅。
mServiceHandler收到消息后陕贮,會(huì)將Intent對(duì)象傳遞給onHandlerIntent方法去處理。注意這個(gè)Intent對(duì)象的內(nèi)容和外界startService(Intent)中的intent的內(nèi)容完全一致的潘飘,通過這個(gè)Intent對(duì)象即可解析出外界啟動(dòng)IntentService時(shí)所傳遞的參數(shù)肮之,通過這些參數(shù)就可區(qū)分具體的后臺(tái)任務(wù),這個(gè)在onHandlerIntent方法中就可以對(duì)不同的后臺(tái)任務(wù)做處理了卜录。當(dāng)onHandlerIntent方法執(zhí)行結(jié)束后戈擒,IntentService會(huì)通過stopSelf()來停止服務(wù),那是因?yàn)閟topSelf()會(huì)立刻停止服務(wù)艰毒,而這個(gè)時(shí)候可能還有其他消息未處理筐高,stopSelf(int startId)則會(huì)等待所有的消息都處理完畢后才終止服務(wù)。一般來說stopSelf(int startId)在嘗試停止服務(wù)之前會(huì)判讀最近啟動(dòng)服務(wù)的次數(shù)是否和startId相等丑瞧,如果相等就立即停止服務(wù)柑土,不相等則不停止服務(wù)。

  • ServiceHandler的實(shí)現(xiàn)
private final class ServiceHandler extends Handler{
    public ServiceHandler(Looper looper){
        super(looper);
    }

    @override
    public void handleMessage(Message msg){
        onHandleIntent((Intent)msg.obj);
        stopSelf(msg.arg1);
    }
}

IntentService的onHandleIntent是一個(gè)抽象方法绊汹,它需要我們?cè)谧宇愔袑?shí)現(xiàn)稽屏,它的作用是從Intent參數(shù)中區(qū)分具體的任務(wù)并執(zhí)行這些任務(wù)。如果目前只存在一個(gè)后臺(tái)任務(wù)灸促,那么onHandleIntent方法執(zhí)行完這個(gè)任務(wù)后诫欠,stopSelf(int startId)就會(huì)直接停止服務(wù);如果目前存在多個(gè)后臺(tái)任務(wù)浴栽,那么當(dāng)onHandleIntent方法執(zhí)行完最后一個(gè)任務(wù)時(shí)荒叼,stopSelf(int startId)才會(huì)直接停止服務(wù)。另外典鸡,由于每執(zhí)行一個(gè)后臺(tái)任務(wù)就必須啟動(dòng)一次IntentService被廓,而IntentService內(nèi)部則通過消息的方式向HandlerThread請(qǐng)求執(zhí)行任務(wù),Handler中Looper是順序處理消息的萝玷,這意味著IntentService也會(huì)順序執(zhí)行后臺(tái)任務(wù)嫁乘,當(dāng)有多個(gè)后臺(tái)任務(wù)同時(shí)存在時(shí),這些后臺(tái)任務(wù)會(huì)按照外界發(fā)起的順序排隊(duì)執(zhí)行球碉。

Android中的線程池

線程池的優(yōu)點(diǎn)
  1. 重用線程池中的線程蜓斧,避免因?yàn)榫€程的創(chuàng)建和銷毀所帶來的性能開銷。
  2. 能有效的控制線程池的最大并發(fā)量睁冬,避免大量的線程因?yàn)閾屨枷到y(tǒng)資源而造成的堵塞的現(xiàn)象挎春。
  3. 能夠?qū)€程進(jìn)行簡單的管理,提供定時(shí)執(zhí)行以及執(zhí)行間隔循環(huán)等功能。
ThreadPoolExecutor
  • 構(gòu)造方法
public ThreadPoolExecutor(int corePoolSize,
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue<Runnable> workQueue,
                        ThreadFactory threadFactory)

corePoolSize 線程池的核心線程數(shù)直奋,默認(rèn)情況下能庆,核心線程會(huì)在線程池中一直存活,即使它們處于閑置狀態(tài)脚线。如果將ThreadPoolExecutor的allowCorePoolTimeOut屬性設(shè)為true搁胆,那么閑置的核心線程在等待執(zhí)行任務(wù)時(shí)會(huì)有超時(shí)策略,超時(shí)時(shí)間由keepAliveTime所指定邮绿。當(dāng)?shù)却龝r(shí)間超過keepAliveTime所指定的時(shí)長后渠旁,核心線程就會(huì)停止。

maximumPoolSize 線程池所能容納的最大線程數(shù)船逮,當(dāng)活動(dòng)線程數(shù)達(dá)到這個(gè)數(shù)值后一死,后續(xù)的新任務(wù)就會(huì)被堵塞。

keepAliveTime 非核心線程閑置時(shí)的超時(shí)時(shí)長傻唾,超過這個(gè)時(shí)長,非核心線程就會(huì)被回收承耿。當(dāng)ThreadPoolExecutor的

allowCorePoolTimeOut屬性為true時(shí)冠骄,keepAliveTime同樣會(huì)作用于核心線程。

unit 用于指定keepAliveTime的時(shí)間單位加袋。

workQueue 線程池中的任務(wù)隊(duì)列凛辣,通過execute提交的runnable對(duì)象會(huì)存儲(chǔ)在這個(gè)參數(shù)中。

threadFactory 線程工廠职烧,為線程池提供創(chuàng)建新線程的功能扁誓。ThreadFactory是一個(gè)接口,它只有一個(gè)方法:Thread newThread
(Runnable r)蚀之。

除了上面的這些主要參數(shù)外蝗敢,ThreadPoolExecutor還有一個(gè)不常用的參數(shù)RejectedExecutionHandler handler。當(dāng)線程無法執(zhí)行新任務(wù)時(shí)足删,這可能是由于任務(wù)隊(duì)列已滿或者是無法成功執(zhí)行任務(wù)寿谴,這個(gè)時(shí)候ThreadPoolExecutor會(huì)調(diào)用handler的rejectedExecution方法來通知調(diào)用者,默認(rèn)情況下rejectedExecution方法會(huì)拋出一個(gè)RejectedExecutionexception失受。
ThreadPoolExecutor為RejectExecutionHandler提供了幾個(gè)可選值:
CallerRunsPolicy讶泰、AbortPolicy、DiscardOldestPolicy拂到,其中AbortPolicy是默認(rèn)值痪署,它會(huì)直接拋出RejectedExecutionException,handler這個(gè)參數(shù)不常用兄旬。

  • ThreadPoolExecutor執(zhí)行任務(wù)時(shí)大致遵循以下原則:
  1. 如果線程池的數(shù)量未達(dá)到核心線程數(shù)量狼犯,那么就會(huì)啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù)。
  2. 如果線程池的線程數(shù)量已達(dá)到或者超過核心線程數(shù)量,那么任務(wù)會(huì)被插入到任務(wù)隊(duì)列中排隊(duì)執(zhí)行辜王。
  3. 如果步驟2中無法將任務(wù)插入到任務(wù)隊(duì)列中劈狐,這往往是由于任務(wù)隊(duì)列已滿,這個(gè)時(shí)候如果線程數(shù)量未達(dá)到線程池規(guī)定的最大值呐馆,那么就會(huì)立即啟動(dòng)一個(gè)非核心線程來執(zhí)行任務(wù)肥缔。
  4. 如果步驟3中線程數(shù)量已達(dá)到線程池所規(guī)定的最大值,那么就拒絕執(zhí)行這次任務(wù)汹来,ThreadPoolExecutor會(huì)調(diào)用RejectedExcutionHandler的rejectedExecution來通知調(diào)用者续膳。
  • ThreadPoolExecutor在AsyncTask中的體現(xiàn)。
private static final int CPU_COUNT = Runtime.getRuntime().AcailableProcessors();

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 ThreadFactory sThreadFactory = new ThreadFactory(){
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r){
        return new Thread(r,"AsyncTask #"+mCount.getAndIncrement());
    }
};

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)

線程池的分類

FixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONEDS,new LinkedBlockingQueue<Runnable>());
}

通過Executors的newFixedThreadPool方法來創(chuàng)建收班,它是一種線程數(shù)量固定的線程池坟岔,當(dāng)線程處于空閑狀態(tài)時(shí),它們并不會(huì)被回收摔桦,除非線程池被關(guān)閉了社付。當(dāng)所有線程都處于活動(dòng)狀態(tài)時(shí),新任務(wù)都會(huì)處于等待狀態(tài)邻耕,直到線程空閑出來鸥咖。由于FixedThreadPool只有核心線程并且核心線程不會(huì)被回收,這意味著他能夠更加快速的響應(yīng)外界的請(qǐng)求兄世。FixedThreadPool中只有核心線程并且核心線程沒有超時(shí)機(jī)制啼辣,另外任務(wù)隊(duì)列也是沒有大小限制。

CachedThreadPool

public static ExecutorService newCachedThreadPool(){
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONEDS,new SynchronousQueue<Runnable>())
}

通過Executors的呢我CachedThreadPool方法來創(chuàng)建御滩。它是一種線程數(shù)量不定的線程池鸥拧,它只是非核心線程,并且其最大線程數(shù)為Integer.MAX_VALUE削解。由于Integer_MAX_VALUE是一個(gè)很大的數(shù)富弦,實(shí)際上就相當(dāng)于最大線程數(shù)可以死任意大。當(dāng)線程池中的線程都處于活動(dòng)狀態(tài)時(shí)氛驮,線程池會(huì)創(chuàng)建新的線程來處理新任務(wù)舆声,否則就會(huì)利用空閑的線程來處理新任務(wù)。線程池中的空閑線程都有超時(shí)機(jī)制柳爽,CachedThreadPool的任務(wù)隊(duì)列其實(shí)相當(dāng)于一個(gè)空集合媳握,這將導(dǎo)致任何任務(wù)都會(huì)立即執(zhí)行,因?yàn)樵谶@種場景下SynchronousQueue是無法插入任務(wù)的磷脯。SynchronousQueue是一個(gè)非常特殊的隊(duì)列蛾找,在很多情況下可以把它簡單理解為一個(gè)無法存儲(chǔ)元素的隊(duì)列,由于它實(shí)際中較少使用赵誓,這里就不深入探討它了打毛。從CachedThreadPool的特性來看柿赊,這類線程池比較適合執(zhí)行大量的耗時(shí)較少的任務(wù)。當(dāng)中整個(gè)線程池都處于閑置狀態(tài)時(shí)幻枉,線程池中的線程都或超時(shí)而被停止碰声,這個(gè)時(shí)候CachedThreadPool之中實(shí)際上是沒有任何線程的,它幾乎不占任何系統(tǒng)資源的熬甫。

ScheduledThreadPool

public static ScheduleExecutorService newScheduledThreadPool(int corePoolSize){
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
    super(corePoolSize,Integer.MAX_VALUE,0,NAMOSECONEDS,new DelayWorkQueue());
}

通過Executors的newScheduledThreadPool方法來創(chuàng)建胰挑。它的核心線程數(shù)量是固定的,而非核心線程是沒有限制的椿肩,并且當(dāng)非核心線程閑置時(shí)會(huì)被立即回收瞻颂。ScheduledThreadPool這列線程池主要用于執(zhí)行定時(shí)任務(wù)和具有固定周期的重復(fù)任務(wù)。

SingleThreadPool

public static ExecutorService newSingleThreadExecutor(){
    return new FinalizableDelegateExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}

通過Executors的newSingleThreadExecutor方法來創(chuàng)建郑象。這類線程池內(nèi)部只有一個(gè)核心線程贡这,它確保所有任務(wù)都在同一個(gè)線程中順序執(zhí)行。SingleThreadExecutor的意義在于統(tǒng)一所有外界任務(wù)到一個(gè)線程中厂榛,這使得在這些任務(wù)之間不需要出來線程同步的問題盖矫。

  • 使用方法
Runnable command = new Runnable(){
    @Override
    public void run(){
        SystemClock.sleep(2000);
    }
};

ExecutorService fixedThreadPool = Executors.newDixedThreadPool(4);
fixedThreadPool.execute(command);

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
cachedThreadPool.execute(command);

ScheduleExecutorsService scheduledThreadPool = Executors.newScheduledThreadPool(4);
//2000ms后執(zhí)行command
scheduledThreadPool.schedule(command,2000,TimeUnit.MILLISECONDS);
//延遲10ms后,每隔1000ms執(zhí)行一次command
scheduledThreadPool.scheduleAtFixedRate(command,10,1000,TimeUnit.MILLISECONDS);

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(command);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末击奶,一起剝皮案震驚了整個(gè)濱河市炼彪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌正歼,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拷橘,死亡現(xiàn)場離奇詭異局义,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)冗疮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門萄唇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人术幔,你說我怎么就攤上這事另萤。” “怎么了诅挑?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵四敞,是天一觀的道長。 經(jīng)常有香客問我拔妥,道長忿危,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任没龙,我火速辦了婚禮铺厨,結(jié)果婚禮上缎玫,老公的妹妹穿的比我還像新娘。我一直安慰自己解滓,他們只是感情好赃磨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洼裤,像睡著了一般邻辉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逸邦,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天恩沛,我揣著相機(jī)與錄音,去河邊找鬼缕减。 笑死雷客,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的桥狡。 我是一名探鬼主播搅裙,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裹芝!你這毒婦竟也來了部逮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤嫂易,失蹤者是張志新(化名)和其女友劉穎兄朋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怜械,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颅和,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缕允。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峡扩。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖障本,靈堂內(nèi)的尸體忽然破棺而出教届,到底是詐尸還是另有隱情,我是刑警寧澤驾霜,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布案训,位于F島的核電站,受9級(jí)特大地震影響粪糙,放射性物質(zhì)發(fā)生泄漏萤衰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一猜旬、第九天 我趴在偏房一處隱蔽的房頂上張望脆栋。 院中可真熱鬧倦卖,春花似錦、人聲如沸椿争。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秦踪。三九已至褐捻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椅邓,已是汗流浹背柠逞。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留景馁,地道東北人板壮。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像合住,于是被迫代替她去往敵國和親绰精。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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

  • 從用途上來說透葛,線程分為主線程和子線程笨使,主線程主要處理和界面相關(guān)的事情,子線程則往往用于執(zhí)行耗時(shí)操作僚害。 除了Thre...
    小柏不是大白閱讀 626評(píng)論 0 3
  • 導(dǎo)語 在Android系統(tǒng)硫椰,線程主要分為主線程和子線程,主線程處理和界面相關(guān)的事情萨蚕,而子線程一般用于執(zhí)行耗時(shí)操作靶草。...
    一個(gè)有故事的程序員閱讀 584評(píng)論 0 3
  • 線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情门岔,而子線程則往往用于執(zhí)行耗時(shí)操作。 AsyncTask封裝了...
    Tom_Ji閱讀 453評(píng)論 0 5
  • 線程 線程在Android中是一個(gè)很重要的概念烤送,從用途上來說寒随,線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事...
    12313凱皇閱讀 1,358評(píng)論 0 1
  • 一帮坚、線程 主線程 主線程是指進(jìn)程中所擁有的線程妻往,在Java中默認(rèn)情況下一個(gè)進(jìn)程只有一個(gè)線程,這個(gè)線程就是主線程试和。 ...
    AR7_閱讀 359評(píng)論 0 2