Android線程池得要這么用

背景

之前寫了兩篇關(guān)于線程和多線程的文章烟很,竟然寫到了多線程,那肯定少不了線程池啊蜓耻,如果想了解線程和線程池方面的知識可以查看我之前寫的
線程你真的了解它嗎
這才是真正的多線程
那么什么是線程池茫舶,它有什么優(yōu)點(diǎn)呢?

  1. 重用線程池中的線程刹淌,避免因?yàn)榫€程的創(chuàng)建和銷毀所帶來的性能開銷饶氏。
    能有效控制線程池的最大并發(fā)數(shù),避免大量的線程之間因相互搶占系統(tǒng)資源而導(dǎo)致的堵塞線程有勾。
  2. 能夠?qū)€程進(jìn)行簡單的管理疹启,并提供定時執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能。
  3. 相對于AsyncTask來說蔼卡,最大的優(yōu)勢在于:線程可控喊崖!比如在離開了某個頁面,提交到AsyncTask不能的任務(wù)不能撤銷雇逞,線程池可以在不需要的時候?qū)⒛硞€線程移除荤懂。

什么是線程池

那么線程池我們該怎么創(chuàng)建呢?首先我們先來看一下創(chuàng)建線程池的構(gòu)造方法

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

我們先來看一下每一個參數(shù)的意義吧喝峦。

  1. corePoolSize:核心池的大小势誊,在創(chuàng)建了線程池后,默認(rèn)情況下谣蠢,線程池中并沒有任何線程粟耻,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù)查近,當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后,就會把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中挤忙。只有當(dāng)工作隊(duì)列滿了的情況下才會創(chuàng)建超出這個數(shù)量的線程霜威。如果某個線程的空閑時間超過了活動時間,那么將標(biāo)記為可回收册烈,并且只有當(dāng)線程池的當(dāng)前大小超過corePoolSize時該線程才會被終止戈泼。用戶可調(diào)用prestartAllCoreThreads()或者prestartCoreThread()方法預(yù)先創(chuàng)建線程,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個線程或者一個線程赏僧。

  2. maximumPoolSize:線程池最大線程數(shù)大猛,這個參數(shù)也是一個非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個線程淀零;當(dāng)大于了這個值就會將Thread由一個丟棄處理機(jī)制來處理挽绩。

  3. keepAliveTime:表示線程沒有任務(wù)執(zhí)行時最多保持多久時間會終止。默認(rèn)情況下驾中,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時唉堪,keepAliveTime才會起作用,直到線程池中的線程數(shù)不大于corePoolSize肩民,即當(dāng)線程池中的線程數(shù)大于corePoolSize時唠亚,如果一個線程空閑的時間達(dá)到keepAliveTime,則會終止持痰,直到線程池中的線程數(shù)不超過corePoolSize灶搜。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時共啃,keepAliveTime參數(shù)也會起作用蝗罗,直到線程池中的線程數(shù)為0逾礁;

  4. Unit:參數(shù)keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態(tài)屬性披粟。

  5. workQueue:一個阻塞隊(duì)列镊靴,用來存儲等待執(zhí)行的任務(wù)盾致,當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后照弥,就會把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中。

  6. threadFactory:線程工廠攻人,主要用來創(chuàng)建線程取试;

  7. handler:表示當(dāng)拒絕處理任務(wù)時的策略,也就是參數(shù)maximumPoolSize達(dá)到后丟棄處理的方法怀吻。有以下四種取值:
    ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常瞬浓。
    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常蓬坡。
    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù)猿棉,然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
    ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
    用戶也可以實(shí)現(xiàn)接口RejectedExecutionHandler定制自己的策略磅叛。

線程池Demo

這個是在網(wǎng)上找的一個簡單的線程池的實(shí)現(xiàn)代碼:

使用動態(tài)代理方式創(chuàng)建建一個ThreadPoolProxyFactory ,里面提供兩種方式獲取線程池:普通線程池和下載的線程池萨赁。

public class ThreadPoolProxyFactory {
    static ThreadPoolProxy mNormalThreadPoolProxy;
    static ThreadPoolProxy mDownLoadThreadPoolProxy;

    /**
     * 得到普通線程池代理對象mNormalThreadPoolProxy
     */
    public static ThreadPoolProxy getNormalThreadPoolProxy() {
        if (mNormalThreadPoolProxy == null) {
            synchronized (ThreadPoolProxyFactory.class) {
                if (mNormalThreadPoolProxy == null) {
                    mNormalThreadPoolProxy = new ThreadPoolProxy(5, 5);
                }
            }
        }
        return mNormalThreadPoolProxy;
    }

    /**
     * 得到下載線程池代理對象mDownLoadThreadPoolProxy
     */
    public static ThreadPoolProxy getDownLoadThreadPoolProxy() {
        if (mDownLoadThreadPoolProxy == null) {
            synchronized (ThreadPoolProxyFactory.class) {
                if (mDownLoadThreadPoolProxy == null) {
                    mDownLoadThreadPoolProxy = new ThreadPoolProxy(3, 3);
                }
            }
        }
        return mDownLoadThreadPoolProxy;
    }
}

線程池代理,替線程池完成一些操作弊琴。提供了三種方法:執(zhí)行任務(wù),提交任務(wù),移除任務(wù)。

public class ThreadPoolProxy {

    ThreadPoolExecutor mExecutor;
    private int mCorePoolSize;
    private int mMaximumPoolSize;


    /**
     * @param corePoolSize    核心池的大小
     * @param maximumPoolSize 最大線程數(shù)
     */
    public ThreadPoolProxy(int corePoolSize, int maximumPoolSize) {
        mCorePoolSize = corePoolSize;
        mMaximumPoolSize = maximumPoolSize;
    }

    /**
     * 初始化ThreadPoolExecutor
     * 雙重檢查加鎖,只有在第一次實(shí)例化的時候才啟用同步機(jī)制,提高了性能
     */
    private void initThreadPoolExecutor() {
        if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
            synchronized (ThreadPoolProxy.class) {
                if (mExecutor == null || mExecutor.isShutdown() || mExecutor.isTerminated()) {
                    long keepAliveTime = 3000;
                    TimeUnit unit = TimeUnit.MILLISECONDS;
                    BlockingQueue workQueue = new LinkedBlockingDeque<>();
                    ThreadFactory threadFactory = Executors.defaultThreadFactory();
                    RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

                    mExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, keepAliveTime, unit, workQueue,
                            threadFactory, handler);
                }
            }
        }
    }
    /**
     執(zhí)行任務(wù)和提交任務(wù)的區(qū)別?
     1.有無返回值
        execute->沒有返回值
        submit-->有返回值
     2.Future的具體作用?
        1.有方法可以接收一個任務(wù)執(zhí)行完成之后的結(jié)果,其實(shí)就是get方法,get方法是一個阻塞方法
        2.get方法的簽名拋出了異常===>可以處理任務(wù)執(zhí)行過程中可能遇到的異常
     */
    /**
     * 執(zhí)行任務(wù)
     */
    public void execute(Runnable task) {
        initThreadPoolExecutor();
        mExecutor.execute(task);
    }

    /**
     * 提交任務(wù)
     */
    public Future submit(Runnable task) {
        initThreadPoolExecutor();
        return mExecutor.submit(task);
    }

    /**
     * 移除任務(wù)
     */
    public void remove(Runnable task) {
        initThreadPoolExecutor();
        mExecutor.remove(task);
    }
}

那么我們要怎么使用線程池呢:

ThreadPoolProxyFactory .getNormalThreadPoolProxy().execute(Runnable);

總結(jié)

這個大概就是Android線程池的使用杖爽,有什么不對的地方歡迎大家留言敲董,我們一起交流,寫下大家慰安。
在網(wǎng)上也看到了一個關(guān)于實(shí)現(xiàn)優(yōu)先級線程池的有興趣的朋友也可以學(xué)習(xí)一下實(shí)現(xiàn)優(yōu)先級線程池腋寨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市化焕,隨后出現(xiàn)的幾起案子精置,更是在濱河造成了極大的恐慌,老刑警劉巖锣杂,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異番宁,居然都是意外死亡元莫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門蝶押,熙熙樓的掌柜王于貴愁眉苦臉地迎上來踱蠢,“玉大人,你說我怎么就攤上這事棋电【ソ兀” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵赶盔,是天一觀的道長企锌。 經(jīng)常有香客問我,道長于未,這世上最難降的妖魔是什么撕攒? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮烘浦,結(jié)果婚禮上抖坪,老公的妹妹穿的比我還像新娘。我一直安慰自己闷叉,他們只是感情好擦俐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著握侧,像睡著了一般蚯瞧。 火紅的嫁衣襯著肌膚如雪嘿期。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天状知,我揣著相機(jī)與錄音秽五,去河邊找鬼。 笑死饥悴,一個胖子當(dāng)著我的面吹牛坦喘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播西设,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼瓣铣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贷揽?” 一聲冷哼從身側(cè)響起棠笑,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎禽绪,沒想到半個月后蓖救,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡印屁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年循捺,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雄人。...
    茶點(diǎn)故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡从橘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出础钠,到底是詐尸還是另有隱情恰力,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布旗吁,位于F島的核電站踩萎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏很钓。R本人自食惡果不足惜驻民,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望履怯。 院中可真熱鬧回还,春花似錦、人聲如沸叹洲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蝗柔,卻和暖如春闻葵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背癣丧。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工槽畔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胁编。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓厢钧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嬉橙。 傳聞我的和親對象是個殘疾皇子早直,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評論 2 345

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