Android的線程池

Android中的線程池來源于Java中的Executor接口,真正的線程池實(shí)現(xiàn)為ThreadPoolExecutor试读,它提供參數(shù)來配置線程池。既然提到線程池,首先得了解線程池有什么有點(diǎn)裂逐,線程池的優(yōu)點(diǎn)主要有以下3點(diǎn):

  1. 線程重用,通過重用線程池中線程避免反復(fù)創(chuàng)建和銷毀縣城帶來的性能開銷問題泣栈。
  2. 控制并發(fā)數(shù)卜高,避免大量線程同時工作搶占系統(tǒng)資源造成阻塞。
  3. 簡單的線程管理南片,實(shí)現(xiàn)定時執(zhí)行等功能掺涛。

一 ThreadPoolExecutor

  1. ThreadPoolExecutor 構(gòu)造器
     //使用給定的參數(shù)和默認(rèn)線程工廠、拒絕執(zhí)行的Handler創(chuàng)建一個新的ThreadPoolExecutor 
     ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
    
     //使用給定的參數(shù)和拒絕執(zhí)行的Handler創(chuàng)建一個新的ThreadPoolExecutor疼进。
     ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
     
     //使用給定的參數(shù)和默認(rèn)線程工廠創(chuàng)建一個新的ThreadPoolExecutor
     ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)

     //使用給定的參數(shù)創(chuàng)建一個新的ThreadPoolExecutor
     ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
 
  1. ThreadPoolExecutor 構(gòu)造器參數(shù)說明
  • corePoolSize 核心線程數(shù)(常駐線程數(shù))
    一直保持在線程池的線程數(shù)薪缆,空閑狀態(tài)也不會退出,除非設(shè)置allowCoreThreadTimeOut為true
  • maximumPoolSize 最大線程數(shù)
    線程池中允許存在的最大線程數(shù)
  • keepAliveTime 保持活躍時間
    當(dāng)線程數(shù)大于核心線程數(shù)時伞广,這是超出空閑線程在終止之前等待新任務(wù)的最大時間拣帽。當(dāng)allowCoreThreadTimeOut為true時,也適用與核心線程
  • unit 單位
    keepAliveTime參數(shù)的時間單位
  • workQueue 任務(wù)隊(duì)列
    在執(zhí)行任務(wù)之前用于保存任務(wù)的隊(duì)列嚼锄。 該隊(duì)列將僅保存由(Runnable的execute)方法提交的任務(wù)减拭。
  • threadFactory 線程工廠
    executor創(chuàng)建新線程的時候使用
  • handler 拒絕執(zhí)行的handler
    當(dāng)線程池?zé)o法執(zhí)行新任務(wù),導(dǎo)致執(zhí)行被阻止時使用的處理程序区丑,可能因?yàn)榫€程達(dá)到線程限制和隊(duì)列容量
  1. ThreadPoolExecutor執(zhí)行任務(wù)時大致規(guī)則
  • 線程池中線程數(shù)小于核心線程數(shù)拧粪,會直接啟動一個核心線程來執(zhí)行新任務(wù)
  • 線程池中線程數(shù)大于等于核心線程數(shù), 將會將新任務(wù)存放到任務(wù)隊(duì)列等待執(zhí)行
  • 線程池中線程數(shù)大于等于核心線程數(shù)刊苍,且任務(wù)隊(duì)列已滿既们,但線程池中線程數(shù)小于最大線程數(shù),將會啟動一個非核心線程來執(zhí)行任務(wù)
  • 線程池中線程數(shù)大于等于最大線程數(shù)正什,那么就會拒絕執(zhí)行該任務(wù)啥纸,調(diào)用handler的rejectedException來通知調(diào)用者
  1. ThreadPoolExecutor在AsyncTask中的使用
    private static final String LOG_TAG = "AsyncTask";

    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    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);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

通過源碼,我們可以看到AsyncTask的THREAD_POOL_EXECUTOR屬性配置如下:

  • 核心線程數(shù)(CORE_POOL_SIZE)為CPU核心數(shù)+1
  • 最大線程數(shù)(MAXIMUM_POOL_SIZE)為CPU核心數(shù) * 2 + 1
  • 非核心線程保持活躍時間為1婴氮,單位為秒
  • 任務(wù)隊(duì)列容量為128

以上對ThreadPoolExecutor和AsyncTask中的ThreadPoolExecutor配置進(jìn)行了介紹斯棒。在Android中通過對ThreadPoolExecutor的配置實(shí)現(xiàn)了四類不同功能特性的線程池盾致,接下來我們就對Android中的這四類線程池進(jìn)行一個簡單介紹

二 FixedThreadPool

通過Executors.newFixedThreadPool創(chuàng)建一個線程池,它使用固定數(shù)量的線程操作了共享無界隊(duì)列荣暮。在任何時候庭惜,大多數(shù)線程都是主動處理任務(wù)的。如果在所有線程處于活動狀態(tài)時提交其他任務(wù)穗酥,則它們將在隊(duì)列中等待护赊,直到有線程空閑可用為止。如果任何線程在關(guān)閉前在執(zhí)行過程中失敗砾跃,如果需要執(zhí)行后續(xù)任務(wù)骏啰,則新線程將取代它。線程池中線程會一致存在抽高,直到線程池明確關(guān)閉(shutdown)判耕。下面是它的實(shí)現(xiàn),可以看到它只有不會被回收的核心線程翘骂,隊(duì)列大小也沒有限制壁熄。

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

三 CachedThreadPool

通過Executors.newCachedThreadPool創(chuàng)建一個線程池,根據(jù)需要創(chuàng)建新線程碳竟,但在可用線程時將重用以前構(gòu)建的線程草丧。這些池通常會提高執(zhí)行許多短期異步任務(wù)的程序的性能。如果先前創(chuàng)建線程可用的話瞭亮,調(diào)用將重用先前構(gòu)建的線程方仿。如果沒有現(xiàn)有的線程可用固棚,一個新線程將被創(chuàng)建并添加到池统翩。未使用六十秒的線程被終止并從緩存中移除。因此此洲,空閑時間足夠長的池不會消耗任何系統(tǒng)資源厂汗。下面是它的實(shí)現(xiàn),可以看到與ThreadPoolExecutor不同的是它沒有核心線程呜师,最大線程數(shù)為Integer.MAX_VALUE娶桦,且CachedThreadPool的任務(wù)隊(duì)列是一個SynchronousQueue的空集合,這將導(dǎo)致任務(wù)會被立即執(zhí)行汁汗,所以這類線程比較適合執(zhí)行大量耗時較少的任務(wù)衷畦。

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

四 ScheduledThreadPool

通過Executors.newScheduledThreadPoo創(chuàng)建一個線程池,可以在給定延遲后調(diào)度命令運(yùn)行知牌,或定期執(zhí)行命令祈争。它有數(shù)量固定的核心線程,且有數(shù)量無限多的非核心線程角寸,但是它的非核心線程超時時間是0s菩混,所以非核心線程一旦空閑立馬就會被回收忿墅。這類線程池適合用于執(zhí)行定時任務(wù)和固定周期的重復(fù)任務(wù)。

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

五 newSingleThreadScheduledExecutor

通過Executors.newSingleThreadScheduledExecutor創(chuàng)建一個單線程執(zhí)行器沮峡,可以在給定延遲后調(diào)度命令運(yùn)行疚脐,或定期執(zhí)行命令。任務(wù)是按順序執(zhí)行的邢疙,在任何給定的時間內(nèi)都不會有一個任務(wù)處于活動狀態(tài)棍弄,讓調(diào)用者可以忽略線程同步問題。

    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

六 線程池一般用法

  • shutDown()疟游,關(guān)閉線程池照卦,需要執(zhí)行完已提交的任務(wù)
  • shutDownNow(),關(guān)閉線程池乡摹,并嘗試結(jié)束已提交的任務(wù)
  • allowCoreThreadTimeOut(boolen)役耕,允許核心線程閑置超時回收
  • execute(),提交任務(wù)無返回值
  • submit()聪廉,提交任務(wù)有返回值

除了上面4種線程池瞬痘,還可以根據(jù)實(shí)際需求自定義線程池。

七 自定義線程池

ExecutorService mExecutor = Executors.newFixedThreadPool(5);

execute()方法板熊,接收一個Runnable對象作為參數(shù)框全,異步執(zhí)行。

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        Log.i("myRunnable", "run");
    }
};
mExecutor.execute(myRunnable);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末干签,一起剝皮案震驚了整個濱河市津辩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌容劳,老刑警劉巖喘沿,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異竭贩,居然都是意外死亡蚜印,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門留量,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窄赋,“玉大人,你說我怎么就攤上這事楼熄∫浯拢” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵可岂,是天一觀的道長错敢。 經(jīng)常有香客問我,道長青柄,這世上最難降的妖魔是什么伐债? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任预侯,我火速辦了婚禮,結(jié)果婚禮上峰锁,老公的妹妹穿的比我還像新娘萎馅。我一直安慰自己,他們只是感情好虹蒋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布糜芳。 她就那樣靜靜地躺著,像睡著了一般魄衅。 火紅的嫁衣襯著肌膚如雪峭竣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天晃虫,我揣著相機(jī)與錄音皆撩,去河邊找鬼。 笑死哲银,一個胖子當(dāng)著我的面吹牛扛吞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荆责,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼滥比,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了做院?” 一聲冷哼從身側(cè)響起盲泛,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎键耕,沒想到半個月后寺滚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡郁竟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年玛迄,在試婚紗的時候發(fā)現(xiàn)自己被綠了由境。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棚亩。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖虏杰,靈堂內(nèi)的尸體忽然破棺而出讥蟆,到底是詐尸還是另有隱情,我是刑警寧澤纺阔,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布瘸彤,位于F島的核電站,受9級特大地震影響笛钝,放射性物質(zhì)發(fā)生泄漏质况。R本人自食惡果不足惜愕宋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望结榄。 院中可真熱鬧中贝,春花似錦、人聲如沸臼朗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽视哑。三九已至绣否,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挡毅,已是汗流浹背蒜撮。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跪呈,地道東北人淀弹。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像庆械,于是被迫代替她去往敵國和親薇溃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

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