Android線程池學(xué)習(xí)總結(jié)

之前的項(xiàng)目中一直沒(méi)有用到線程池,對(duì)這個(gè)概念也不太熟悉,最近看書的時(shí)候看到線程池,學(xué)習(xí)了它在Android中的應(yīng)用,來(lái)總結(jié)記錄一下。

線程池:線程池是一個(gè)對(duì)象池(String也有一個(gè)字符串對(duì)象池,當(dāng)我們用"123"這樣的形式聲明一個(gè)字符串對(duì)象時(shí),jvm會(huì)先在String對(duì)象池中找有沒(méi)有這個(gè)字符串對(duì)象,如果有,就將這個(gè)字符串對(duì)象的引用直接返回就可以,如果沒(méi)有,就在String對(duì)象池中先創(chuàng)建一個(gè)"123"的字符串對(duì)象),所有對(duì)象池都有一個(gè)共性,就是最大程度的復(fù)用對(duì)象,省去了重復(fù)創(chuàng)建,銷毀對(duì)象的時(shí)間開(kāi)銷。而線程池就是管理線程,最大程度的利用線程。當(dāng)有線程任務(wù)時(shí),從池中取一個(gè)線程來(lái)執(zhí)行任務(wù),執(zhí)行結(jié)束之后,線程對(duì)象歸池。

進(jìn)程和線程:關(guān)于進(jìn)程和線程需要提一下,一個(gè)進(jìn)程可以有多個(gè)線程,每個(gè)進(jìn)程有獨(dú)立的運(yùn)行空間,而所有的線程共享一片內(nèi)存空間,而每個(gè)線程有獨(dú)立的??臻g也存儲(chǔ)線程執(zhí)行過(guò)程中的數(shù)據(jù)。

線程池的優(yōu)點(diǎn):

  1. 避免頻繁的創(chuàng)建和銷毀線程帶來(lái)的時(shí)間開(kāi)銷。
  2. 避免多個(gè)線程之間因搶占系統(tǒng)資源導(dǎo)致的線程阻塞。
  3. 能夠?qū)€程進(jìn)行簡(jiǎn)單的管理,提供間隔執(zhí)行,定時(shí)執(zhí)行等功能。

子線程和主線程

Android的主線程就是UI線程,UI線程負(fù)責(zé)和用戶進(jìn)行交互,保持高度的響應(yīng),所以在主線程中不能加入耗時(shí)操作,避免線程不能及時(shí)響應(yīng)用戶操作,出現(xiàn)ANR現(xiàn)象。而在Android3.0之后,所有的網(wǎng)絡(luò)請(qǐng)求都不允許在主線程執(zhí)行,也是因?yàn)檫@個(gè)原因。所以我們通常會(huì)開(kāi)啟一個(gè)線程來(lái)執(zhí)行耗時(shí)任務(wù)。

1.子線程和主線程交互問(wèn)題

在子線程從進(jìn)行耗時(shí)任務(wù),在任務(wù)完成之后需要通知用戶,這個(gè)時(shí)候就需要更新UI。Android的UI線程是線程不安全的,如果想要更新UI,必須在主線程中進(jìn)行。這個(gè)時(shí)候,我們可以考慮使用Handler。

在子線程中發(fā)送消息,由主線程中的Handler接收,并進(jìn)行消息處理。

注:這里只是簡(jiǎn)單演示一下,實(shí)際開(kāi)發(fā)中的Handler不能這樣寫,要寫成靜態(tài)匿名內(nèi)部類+軟引用的方式,否則很容易引起內(nèi)存泄漏,由于此次的重點(diǎn)不在這里,就不詳細(xì)說(shuō)了,貼一篇我看過(guò)的文章,這里寫的很詳細(xì),感興趣的可以看一下,Android 內(nèi)存泄露總結(jié) .

//主線程中
private Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case UPDATE_TEXT:
                // 在這里可以進(jìn)行UI操作
                text.setText("Nice to meet you");
                break;
            default:
                break;
        }
    }
};


 //子線程中
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 將Message對(duì)象發(fā)送出去
異步消息處理機(jī)制

Android中的異步消息主要由4部分構(gòu)成,Handler,Message,MessageQueue,Lopper.

Message:在線程之間傳遞的消息,內(nèi)部可攜帶少量信息。
Handler:處理和發(fā)送消息,sendMessage()和handleMessage().
MessageQueue:消息隊(duì)列,用于存放Handler發(fā)送的消息,消息隊(duì)列中的消息等待被處理,每個(gè)線程只有一個(gè)MessageQueue.
Lopper:線程中的MessageQueue的管家,調(diào)用Lopper的loop()就會(huì)進(jìn)入無(wú)限循環(huán)中,每當(dāng)MessageQueue中有消息,Looper就會(huì)將它取出,傳遞到Handler的handleMessage()方法中。每個(gè)線程中只有一個(gè)Looper。

經(jīng)過(guò)下面的處理過(guò)程,消息就從子線程回到了主線程中。

處理過(guò)程

線程池

Java中線程池的頂級(jí)是Excutor,而真正的實(shí)現(xiàn)類是ExcutorService,ExcutorService的默認(rèn)實(shí)現(xiàn)是ThreadPoolExcutor,可以使用Excutors類中的方法自動(dòng)創(chuàng)建線程池。

Excutors中默認(rèn)實(shí)現(xiàn)的幾種線程:

newCachedThreadPool:返回一個(gè)能根據(jù)實(shí)際情況調(diào)整線程池中線程數(shù)量的線程池,也就是說(shuō),線程的數(shù)量是不固定的。調(diào)用 execute() 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒(méi)有可用的,則創(chuàng)建一個(gè)新線程并添加到池中,去處理新任務(wù)。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程(60s是該線程的默認(rèn)“保持活動(dòng)時(shí)間”)。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源。注意,可以使用 ThreadPoolExecutor 構(gòu)造方法創(chuàng)建具有類似屬性但細(xì)節(jié)不同(例如超時(shí)參數(shù))的線程池。

newFixedThreadPool:返回一個(gè)有固定線程數(shù)量的線程池,每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小,線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。如果有新任務(wù)提交,但是沒(méi)有空閑線程來(lái)處理,線程數(shù)量已經(jīng)達(dá)到了最大值,這時(shí)任務(wù)會(huì)被加入任務(wù)隊(duì)列中,等待空閑線程來(lái)執(zhí)行。

newSingleThreadExecutor:創(chuàng)建是一個(gè)單線程池,也就是該線程池只有一個(gè)線程在工作,所有的任務(wù)是串行執(zhí)行的,如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來(lái)替代它,此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。該線程池每次只能只執(zhí)行一個(gè)線程任務(wù),多余的任務(wù)放入任務(wù)隊(duì)列,等待順序執(zhí)行。

newScheduledThreadPool:創(chuàng)建一個(gè)大小無(wú)限的線程池,此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

ThreadPoolExcutor構(gòu)造函數(shù),相關(guān)參數(shù)說(shuō)明:

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

1)corePoolSize:線程池的核心線程數(shù),一般情況下不管有沒(méi)有任務(wù)都會(huì)一直在線程池中一直存活,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 設(shè)置為 true 時(shí),閑置的核心線程會(huì)存在超時(shí)機(jī)制,如果在指定時(shí)間沒(méi)有新任務(wù)來(lái)時(shí),核心線程也會(huì)被終止,而這個(gè)時(shí)間間隔由第3個(gè)屬性 keepAliveTime 指定。

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

3)keepAliveTime:控制線程閑置時(shí)的超時(shí)時(shí)長(zhǎng),超過(guò)則終止該線程。一般情況下用于非核心線程,只有在ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 設(shè)置為 true時(shí),也作用于核心線程。

4)unit:用于指定 keepAliveTime 參數(shù)的時(shí)間單位,TimeUnit 是個(gè) enum 枚舉類型,常用的有:TimeUnit.HOURS(小時(shí))、TimeUnit.MINUTES(分鐘)、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒)等。

5)workQueue:線程池的任務(wù)隊(duì)列,通過(guò)線程池的 execute(Runnable command) 方法會(huì)將任務(wù) Runnable 存儲(chǔ)在隊(duì)列中。

6)threadFactory:線程工廠,它是一個(gè)接口,用來(lái)為線程池創(chuàng)建新線程的。

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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