android線(xiàn)程及線(xiàn)程池

眾所周知,在UI系統(tǒng)中進(jìn)行一些耗時(shí)操作,都會(huì)導(dǎo)致卡頓現(xiàn)象,因?yàn)橐淮嗡⑿略?6ms,如果當(dāng)次操作過(guò)了這個(gè)時(shí)間,那么用戶(hù)就能感覺(jué)到明顯的卡頓,甚至引起ANR 。
對(duì)于這種情況,一般都是再起一個(gè)線(xiàn)程,進(jìn)行一些耗時(shí)的操作,通過(guò)繼承Thread 或者實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法,來(lái)實(shí)現(xiàn)創(chuàng)建新線(xiàn)程,進(jìn)行耗時(shí)操作的需求.由于java的單繼承關(guān)系,首推實(shí)現(xiàn)Runnable方法,這樣不會(huì)太過(guò)臃腫。

private void runThread() {
        Thread t1 = new Thread(new MyRunnable(this), "郭富城");
        t1.start();
      //強(qiáng)調(diào)一點(diǎn),調(diào)用run方法是真的調(diào)用方法,而調(diào)用start方法則會(huì)創(chuàng)建新線(xiàn)程去調(diào)用這個(gè)run方法。
    }

//實(shí)現(xiàn)runnable方法  至于繼承Thread方法的代碼 ,就不寫(xiě)了
    static class MyRunnable implements Runnable {
        private WeakReference<MainActivity> reference;

        MyRunnable(MainActivity activity) {
            reference = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void run() {
            if (reference != null) {
                MainActivity activity = reference.get();
                if (activity != null) {
                    //子線(xiàn)程不能彈toast的 所以加了點(diǎn)東西
                    Looper.prepare();
                    Toast.makeText(activity, Thread.currentThread().getName() + " is Runing", Toast.LENGTH_SHORT).show();
                    Looper.loop();
                }
            }
        }
    }

另外,jdk1.5版本以后,就新加了個(gè)Callable接口,相較于Runnable接口,他可以定義返回值,并且可以?huà)伋霎惓#枰獙?shí)現(xiàn)的方法也從run方法變成了call方法。還有一點(diǎn)很有意思,他返回一個(gè)Future對(duì)象,通過(guò)這個(gè)對(duì)象,我們可以知道任務(wù)的進(jìn)行程序,并且可以關(guān)閉這個(gè)任務(wù)。Thread是不支持這個(gè)接口的 ,所以如果要用Callable,就需要用上FutureTask.

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

簡(jiǎn)單的說(shuō),F(xiàn)utureTask是一種可以取消的異步任務(wù),異步執(zhí)行任務(wù), 可以開(kāi)始、取消以及查看任務(wù)是否完成, 如果任務(wù)沒(méi)有執(zhí)行完,get方法會(huì)導(dǎo)致線(xiàn)程阻塞, 一旦一個(gè)執(zhí)行任務(wù)已經(jīng)完成就不能再次開(kāi)始和結(jié)束(除非執(zhí)行時(shí)通過(guò)runAndReset()方法.另外,F(xiàn)utureTask也同樣支持Runnable接口。

 private void runFutureTask() {
        //創(chuàng)建線(xiàn)程池 不用線(xiàn)程池 直接用future也可以的
        final ExecutorService exec = Executors.newFixedThreadPool(5);
        //創(chuàng)建futureTask任務(wù)
        final FutureTask<String> ft = new FutureTask<String>(new MyCallable());
        // 執(zhí)行也可以 提交也可以 還有種invokeAll方法
        exec.execute(ft);
//        exec.submit(ft);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //get方法會(huì)自動(dòng)阻塞當(dāng)前線(xiàn)程  直到拿到結(jié)果
                    //所以不要放在主線(xiàn)程去get 不然就卡住了 雖然我試過(guò)卡個(gè)15秒也沒(méi)事
                    final String text = ft.get();
                    Looper.prepare();
                    Toast.makeText(FutureTaskActivity.this, text, Toast.LENGTH_SHORT).show();
                    Looper.loop();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //用完線(xiàn)程池 記得關(guān)閉掉
        exec.shutdown();
    }

    static class MyCallable implements Callable<String> {

        @Override
        public String call() throws Exception {
            Thread.sleep(3000);
            return "代碼讓我快樂(lè),代碼讓我禿頂";
        }
    }

線(xiàn)程是CPU調(diào)度的最小單元,對(duì)于線(xiàn)程的創(chuàng)建,銷(xiāo)毀,調(diào)度,其實(shí)也是在耗費(fèi)一定資源的,特別是某些情況下,你需要?jiǎng)?chuàng)建一堆線(xiàn)程進(jìn)行一些簡(jiǎn)單的耗時(shí)操作時(shí),這個(gè)資源的消耗量還是非常大的,所以就有線(xiàn)程池的需求了。

我們來(lái)總結(jié)一下優(yōu)點(diǎn)吧。
1.重用線(xiàn)程池中的線(xiàn)程,避免頻繁地創(chuàng)建和銷(xiāo)毀線(xiàn)程帶來(lái)的性能消耗;
2.有效控制線(xiàn)程的最大并發(fā)數(shù)量,防止線(xiàn)程過(guò)大導(dǎo)致?lián)屨假Y源造成系統(tǒng)阻塞;
3.可以對(duì)線(xiàn)程進(jìn)行一定地管理。

使用線(xiàn)程池 相對(duì)于每次都new 線(xiàn)程,性能會(huì)好很多,并且可以統(tǒng)一管理,功能上也能有所改善,如果需要定時(shí)執(zhí)行,定期執(zhí)行,線(xiàn)程中斷等。
減少內(nèi)存開(kāi)銷(xiāo)。

ThreadPoolExecutor:
  ExecutorService是最初的線(xiàn)程池接口,ThreadPoolExecutor類(lèi)是對(duì)線(xiàn)程池的具體實(shí)現(xiàn),它通過(guò)構(gòu)造方法來(lái)配置線(xiàn)程池的參數(shù),我們來(lái)分析一下它常用的構(gòu)造函數(shù)吧。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

參數(shù)解釋?zhuān)?
    corePoolSize,線(xiàn)程池中核心線(xiàn)程的數(shù)量,默認(rèn)情況下,即使核心線(xiàn)程沒(méi)有任務(wù)在執(zhí)行它也存在的,我們固定一定數(shù)量的核心線(xiàn)程且它一直存活這樣就避免了一般情況下CPU創(chuàng)建和銷(xiāo)毀線(xiàn)程帶來(lái)的開(kāi)銷(xiāo)。我們?nèi)绻麑hreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true,那么閑置的核心線(xiàn)程就會(huì)有超時(shí)策略,這個(gè)時(shí)間由keepAliveTime來(lái)設(shè)定,即keepAliveTime時(shí)間內(nèi)如果核心線(xiàn)程沒(méi)有回應(yīng)則該線(xiàn)程就會(huì)被終止。allowCoreThreadTimeOut默認(rèn)為false,核心線(xiàn)程沒(méi)有超時(shí)時(shí)間。
    maximumPoolSize,線(xiàn)程池中的最大線(xiàn)程數(shù),當(dāng)任務(wù)數(shù)量超過(guò)最大線(xiàn)程數(shù)時(shí)其它任務(wù)可能就會(huì)被阻塞。最大線(xiàn)程數(shù)=核心線(xiàn)程+非核心線(xiàn)程。非核心線(xiàn)程只有當(dāng)核心線(xiàn)程不夠用且線(xiàn)程池有空余時(shí)才會(huì)被創(chuàng)建,執(zhí)行完任務(wù)后非核心線(xiàn)程會(huì)被銷(xiāo)毀。
    keepAliveTime,非核心線(xiàn)程的超時(shí)時(shí)長(zhǎng),當(dāng)執(zhí)行時(shí)間超過(guò)這個(gè)時(shí)間時(shí),非核心線(xiàn)程就會(huì)被回收。當(dāng)allowCoreThreadTimeOut設(shè)置為true時(shí),此屬性也作用在核心線(xiàn)程上。
    unit,枚舉時(shí)間單位,TimeUnit。
    workQueue,線(xiàn)程池中的任務(wù)隊(duì)列,我們提交給線(xiàn)程池的runnable會(huì)被存儲(chǔ)在這個(gè)對(duì)象上。

線(xiàn)程池的分配遵循這樣的規(guī)則:

    當(dāng)線(xiàn)程池中的核心線(xiàn)程數(shù)量未達(dá)到最大線(xiàn)程數(shù)時(shí),啟動(dòng)一個(gè)核心線(xiàn)程去執(zhí)行任務(wù);
    如果線(xiàn)程池中的核心線(xiàn)程數(shù)量達(dá)到最大線(xiàn)程數(shù)時(shí),那么任務(wù)會(huì)被插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行;
    如果在上一步驟中任務(wù)隊(duì)列已滿(mǎn)但是線(xiàn)程池中線(xiàn)程數(shù)量未達(dá)到限定線(xiàn)程總數(shù),那么啟動(dòng)一個(gè)非核心線(xiàn)程來(lái)處理任務(wù);
    如果上一步驟中線(xiàn)程數(shù)量達(dá)到了限定線(xiàn)程總量,那么線(xiàn)程池則拒絕執(zhí)行該任務(wù),且ThreadPoolExecutor會(huì)調(diào)用RejectedtionHandler的rejectedExecution方法來(lái)通知調(diào)用者。

四種線(xiàn)程池 都可以通過(guò)Executors提供:

  1. newCachedThreadPool:創(chuàng)建一個(gè)可緩存線(xiàn)程池,他是一個(gè)不限容量的線(xiàn)程池,其中創(chuàng)建的所有的線(xiàn)程都是非核心線(xiàn)程,如果線(xiàn)程池長(zhǎng)度超過(guò)處理需要,超時(shí)時(shí)間設(shè)置為60s,如果當(dāng)前沒(méi)有任務(wù),會(huì)回收空閑線(xiàn)程,若無(wú)可回收,則新建線(xiàn)程。用于執(zhí)行一些生存期很短的異步型任務(wù)
public static ExecutorService new CachedThreadPool(){
    return new ThreadPoolExecutor(
        0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>()
    );
}
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  1. newFixedThreadPool :創(chuàng)建一個(gè)定長(zhǎng)線(xiàn)程池,可控制線(xiàn)程最大并發(fā)數(shù),超出的線(xiàn)程會(huì)在隊(duì)列中等待。池線(xiàn)程數(shù)固定,創(chuàng)建的線(xiàn)程會(huì)一直存在。它沒(méi)有超時(shí)機(jī)制并且等待隊(duì)列無(wú)限常,所以fixedThreadPool多數(shù)針對(duì)一些很穩(wěn)定很固定的正規(guī)并發(fā)線(xiàn)程,多用于服務(wù)器。
public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(
        nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>() 
        );
}
//創(chuàng)建線(xiàn)程池
ExecutorService mExecutor = Executors.newFixedThreadPool(5);//參數(shù)即核心線(xiàn)程數(shù)
  1. newScheduledThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線(xiàn)程池,其實(shí)他將上面兩種線(xiàn)程池的優(yōu)點(diǎn)全部集結(jié)成一塊,他有一定數(shù)量的核心線(xiàn)程,并且無(wú)限容量的非核心線(xiàn)程,區(qū)別在于非核心線(xiàn)程的超時(shí)時(shí)間設(shè)定為0秒,即一旦空閑,立馬回收,支持定時(shí)及周期性任務(wù)執(zhí)行。
public static ScheduledThreadPool newScheduledThreadPool(int corePoolSize){
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);//核心線(xiàn)程數(shù)
  1. newSingleThreadExecutor 創(chuàng)建一個(gè)單線(xiàn)程化的線(xiàn)程池,他只有一個(gè)核心線(xiàn)程,它也只會(huì)用唯一的工作線(xiàn)程來(lái)執(zhí)行任務(wù),可以讓調(diào)用者忽略線(xiàn)程同步的問(wèn)題。
public static ExecutorService newSingleThreadExecutor(){
    return new FinalizableDelegatedExecutorService(
        new ThreadPoolExecutor(
        1, 1, 0L, TimeUnit.MILLISECONDS, 
        new LinkedBlockingQueue<Runnable>()));
}
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

線(xiàn)程池一般用法

    shutDown(),關(guān)閉線(xiàn)程池,需要執(zhí)行完已提交的任務(wù);
    shutDownNow(),關(guān)閉線(xiàn)程池,并嘗試結(jié)束已提交的任務(wù);
    allowCoreThreadTimeOut(boolen),允許核心線(xiàn)程閑置超時(shí)回收;
    execute(),提交任務(wù)無(wú)返回值;
    submit(),提交任務(wù)有返回值;

newCachedThreadPool緩存線(xiàn)程池,如果線(xiàn)程超出則靈活回收,如果不夠則創(chuàng)建
newFixedThreadPool 定長(zhǎng)線(xiàn)程池,可以設(shè)置最大線(xiàn)程數(shù),超出的任務(wù)在隊(duì)列中等候。
newScheduledThreadPool 也是定長(zhǎng)線(xiàn)程池 ,支持定時(shí)及周期性任務(wù)。
newSingleThreadExecutor 單線(xiàn)程化的線(xiàn)程池,任務(wù)根據(jù)加入順序在隊(duì)列中慢慢等待執(zhí)行。

除了以上這些,在Android中充當(dāng)線(xiàn)程的角色還有AsyncTask、HandlerThread、IntentService。它們本質(zhì)上都是由Handler+Thread來(lái)構(gòu)成的。

AsyncTask,它封裝了線(xiàn)程池和Handler,主要為我們?cè)谧泳€(xiàn)程中更新UI提供便利。
HandlerThread,它是個(gè)具有消息隊(duì)列的線(xiàn)程,可以方便我們?cè)谧泳€(xiàn)程中處理不同的事務(wù)。
IntentService,我們可以將它看做為HandlerThread的升級(jí)版,它是服務(wù),優(yōu)先級(jí)更高。

參考
http://blog.csdn.net/weixin_36244867/article/details/72832632
http://blog.csdn.net/linchunquan/article/details/22382487
http://www.hchstudio.cn/2017/04/01/FutureTask%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/
http://www.cnblogs.com/wenjiang/archive/2012/09/02/2668089.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,963評(píng)論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,348評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,083評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,706評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,442評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,802評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,795評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,983評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,542評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,287評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,486評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,030評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,710評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,116評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,412評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,224評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,462評(píng)論 2 378

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

  • 前段時(shí)間遇到這樣一個(gè)問(wèn)題,有人問(wèn)微信朋友圈的上傳圖片的功能怎么做才能讓用戶(hù)的等待時(shí)間較短,比如說(shuō)一下上傳9張圖片,...
    加油碼農(nóng)閱讀 1,215評(píng)論 0 2
  • 原文鏈接:http://blog.csdn.net/u010687392/article/details/4985...
    xpengb閱讀 1,343評(píng)論 0 1
  • 目前的工作是接觸大數(shù)據(jù)相關(guān)的內(nèi)容,自己也缺少高并發(fā)的知識(shí),剛好前幾天看了flume的源碼,里面也用到了各種線(xiàn)程池內(nèi)...
    等一夏_81f7閱讀 1,428評(píng)論 0 0
  • 先看幾個(gè)概念:線(xiàn)程:進(jìn)程中負(fù)責(zé)程序執(zhí)行的執(zhí)行單元。一個(gè)進(jìn)程中至少有一個(gè)線(xiàn)程。多線(xiàn)程:解決多任務(wù)同時(shí)執(zhí)行的需求,合理...
    yeying12321閱讀 563評(píng)論 0 0
  • 中午突然想做憤怒靜心!又不知道該表達(dá)什么!于是就一直說(shuō):我很生氣,我很生氣……同時(shí)用棍子敲打枕頭! 然后開(kāi)始表達(dá)對(duì)...
    竺子閱讀 104評(píng)論 0 0