線程池的好處
在做網(wǎng)站、網(wǎng)站設(shè)計過程中,需要針對客戶的行業(yè)特點、產(chǎn)品特性、目標受眾和市場情況進行定位分析,以確定網(wǎng)站的風格、色彩、版式、交互等方面的設(shè)計方向。創(chuàng)新互聯(lián)建站還需要根據(jù)客戶的需求進行功能模塊的開發(fā)和設(shè)計,包括內(nèi)容管理、前臺展示、用戶權(quán)限管理、數(shù)據(jù)統(tǒng)計和安全保護等功能。
1、重用線程池中的線程,避免線程的創(chuàng)建與銷毀帶來的性能開銷
2、能有效控制線程池的最大并發(fā)數(shù),避免大量線程因搶占資源而導致的阻塞
3、能對線程進行簡單的管理,提供定時或者指定間隔時間、循環(huán)執(zhí)行等操作
線程池的概率來自于java的Executor接口,實現(xiàn)類是ThreadPoolExecutor, 它提供一系列的參數(shù)來配置線程池,以此構(gòu)建不同的線程池。Android的線程池分4類,都是通過Executors所提供的工廠方法來得到。
ThreadPoolExecutor有四個構(gòu)造函數(shù),下面這個是最常用的
public?ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnnable workQueue, ThreadFactory threadFactory)
corePoolSize
線程池中的核心線程數(shù),默認情況下核心線程會在線程池中一直存活,即使他們處于閑置狀態(tài)。如果設(shè)置ThreadPoolExecutor 中的allowCoreThreadTimeOut = true, 核心線程在等待新任務(wù)到來時有超時機制,時間超過keepAliveTime所指定的時間后,核心線程會終止。
maximumPoolSize
最大線程數(shù)
keepAliveTime
非核心線程閑置的超時時間,超過這個時間,非核心線程會被回收。核心線程則要看allowCoreThreadTimeOut屬性的值。
unit
時間單位
workQueue
線程池中的工作隊列
threadFactory
線程工廠,為線程池提供創(chuàng)建新線程的功能。
舉個例子,我們常用的okhttp內(nèi)部也是使用了線程池,它的ThreadPoolExecutor主要是定義在Dispatcher類里面。 使用的是CachedThreadPool。
executorService = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, SynchronousQueue(), ThreadFactory("okhttp Dispatcher", false))
1、FixedThreadPool
通過Executors的newFixedThreadPool()創(chuàng)建,這是一個線程數(shù)量固定的線程池,里面所有的線程都是核心線程。
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads, nThreads, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable())
}
2、CachedThreadPool
通過Executors的newCacheThreadPool()創(chuàng)建,這是一個線程數(shù)量不定的線程池,里面所有的線程都是非核心線程。最大線程數(shù)是無限大,當線程池中的線程都處于活動狀態(tài)時,新的task會創(chuàng)建新的線程來處理,否則就使用空閑的線程處理,所有的線程都是60s的超時時間,超時后會自動回收。
public static ExecutorService?newFixedThreadPool(){
return new ThreadPoolExecutor(0,?Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueueRunnable())
}
3、ScheduledThreadPool
通過Executors的newScheduledThreadPool()創(chuàng)建, 核心線程固定,非核心線程無限大,當非核心線程空閑時,會立即被回收。適合做定時任務(wù)或者固定周期的重復任務(wù)。
public static ExecutorService?newScheduledThreadPool(int corePoolSize){
return new ThreadPoolExecutor(corePoolSize,?Integer.MAX_VALUE, 0, TimeUnit.SECONDS, new DelayedWorkQueue())
}
4、SingleThreadExcecutor
通過Executors的newSingleThreadPool()創(chuàng)建,內(nèi)部只有一個核心線程。
public static ExecutorService?newFixedThreadPool(){
return new ThreadPoolExecutor(1,?1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueueRunnable())
}
課外知識:LinkedBlockingQueue
LinkedBlockingQueue是由鏈表組成的阻塞隊列,內(nèi)部head 指向隊列第一個元素,last指向最后一個元素。入隊和出隊都會加鎖阻塞,都是使用了不同的鎖。
DelayedWorkQueue
延時隊列,隊內(nèi)元素必須是Delayed的實現(xiàn)類。對內(nèi)元素會按照Delayed時間進行排序,對內(nèi)元素只有在delayed時間過期了才能出隊。
入隊的時候不阻塞隊列,出隊的時候,如果隊列為空或者隊列里所有元素都等待時間都沒有到期,則該線程進入阻塞狀態(tài)。
異步通信機制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現(xiàn) 工作線程對UI的更新處理,最終實現(xiàn)異步消息的處理。Handler不僅僅能將子線程的數(shù)據(jù)傳遞給主線程,它能實現(xiàn)任意兩個線程的數(shù)據(jù)傳遞。
(1)Message
Message 可以在線程之間傳遞消息??梢栽谒膬?nèi)部攜帶少量數(shù)據(jù),用于在不同線程之間進行數(shù)據(jù)交換。除了 what 字段,還可以使用 arg1 和 arg2 來攜帶整型數(shù)據(jù),使用 obj 來攜帶 Object 數(shù)據(jù)。
(2) Handler
Handler 作為處理中心,用于發(fā)送(sendMessage 系列方法)與處理消息(handleMessage 方法)。
(3) MessageQueue
MessageQueue 用于存放所有通過 Handler 發(fā)送的消息。這部分消息會一直存放在消息隊列中,直到被處理。每個線程中只會有一個 MessageQueue 對象
(4) Looper
Looper 用于管理 MessageQueue 隊列,Looper對象通過loop()方法開啟了一個死循環(huán)——for (;;){},不斷地從looper內(nèi)的MessageQueue中取出Message,并傳遞到 Handler 的 handleMessage() 方法中。每個線程中只會有一個 Looper 對象。
AsyncTask 是一種輕量級的任務(wù)異步類,可以在后臺子線程執(zhí)行任務(wù),且將執(zhí)行進度及執(zhí)行結(jié)果傳遞給 UI 線程。
(1)onPreExecute()
在 UI 線程上工作,在任務(wù)執(zhí)行 doInBackground() 之前調(diào)用。此步驟通常用于設(shè)置任務(wù),例如在用戶界面中顯示進度條。
(2)doInBackground(Params... params)
在子線程中工作,在 onPreExecute() 方法結(jié)束后執(zhí)行,這一步被用于在后臺執(zhí)行長時間的任務(wù),Params 參數(shù)通過 execute(Params) 方法被傳遞到此方法中。任務(wù)執(zhí)行結(jié)束后,將結(jié)果傳遞給 onPostExecute(Result) 方法,同時我們可以通過 publishProgress(Progress) 方法,將執(zhí)行進度發(fā)送給 onProgressUpdate(Progress) 方法。
(3)onProgressUpdate(Progress... values)
在 UI 線程上工作,會在 doInBackground() 中調(diào)用 publishProgress(Progress) 方法后執(zhí)行,此方法用于在后臺計算仍在執(zhí)行時(也就是 doInBackgound() 還在執(zhí)行時)將計算執(zhí)行進度通過 UI 顯示出來。例如,可以通過動畫進度條或顯示文本字段中的日志,從而方便用戶知道后臺任務(wù)執(zhí)行的進度。
(4)onPostExecute(Result result)
在 UI 線程上工作,在任務(wù)執(zhí)行完畢(即 doInBackground(Result) 執(zhí)行完畢)并將執(zhí)行結(jié)果傳過來的時候工作。
使用規(guī)則:
(1)AsyncTask 是個抽象類,所以要創(chuàng)建它的子類實現(xiàn)抽象方法
(1)AsyncTask 類必須是在 UI 線程中被加載,但在Android 4.1(API 16)開始,就能被自動加載完成。
(2)AsyncTask 類的實例對象必須在 UI 線程中被創(chuàng)建。
(3)execute() 方法必須是在 UI 線程中被調(diào)用。
(4)不要手動調(diào)用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()
(5)任務(wù)只能執(zhí)行一次(如果嘗試第二次執(zhí)行,將拋出異常)。即一個AsyncTask對象只能調(diào)用一次execute()方法。
原理:
? ? ? 其源碼中原理還是 Thread 與 Handler 的實現(xiàn),其包含 兩個線程池,一個 Handler,如下所示:
名稱類型作用
SERIAL_EXECUTOR線程池分發(fā)任務(wù),串行分發(fā),一次只分發(fā)一個任務(wù)
THREAD_POOL_EXECUTOR線程池執(zhí)行任務(wù),并行執(zhí)行,執(zhí)行的任務(wù)由 SERIAL_EXECUTOR 分發(fā)
InternalHandlerHandler負責子線程與主線程的溝通,通知主線程做 UI 工作
一方面減少了每個并行任務(wù)獨自建立線程的開銷,另一方面可以管理多個并發(fā)線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務(wù)的執(zhí)行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝。
Executors提供了四種創(chuàng)建ExecutorService的方法,他們的使用場景如下:
1. Executors.newFixedThreadPool()
創(chuàng)建一個定長的線程池,每提交一個任務(wù)就創(chuàng)建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。
當線程處于空閑狀態(tài)時,它們并不會被回收,除非線程池被關(guān)閉。當所有的線程都處于活動狀態(tài)時,新任務(wù)都會處于等待狀態(tài),直到有線程空閑出來。
只有核心線程并且不會被回收,能夠更加快速的響應外界的請求。
2. Executors.newCachedThreadPool()
創(chuàng)建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時,它可以靈活的添加新的線程,而不會對池的長度作任何限制
線程數(shù)量不定的線程池,只有非核心線程,最大線程數(shù)為 Integer.MAX_VALUE。當線程池中的線程都處于活動狀態(tài)時,線程池會創(chuàng)建新的線程來處理新任務(wù),否則利用空閑的線程來處理新任務(wù)。線程池中的空閑線程具有超時機制,為 60s。
任務(wù)隊列相當于一個空集合,導致任何任務(wù)都會立即被執(zhí)行,適合執(zhí)行大量耗時較少的任務(wù)。當整個線程池都處于限制狀態(tài)時,線程池中的線程都會超時而被停止。
3. Executors.newScheduledThreadPool()
創(chuàng)建一個定長的線程池,而且支持定時的以及周期性的任務(wù)執(zhí)行,類似于Timer。
非核心線程數(shù)沒有限制,并且非核心線程閑置的時候立即回收,主要用于執(zhí)行定時任務(wù)和具有固定周期的重復任務(wù)。
4. Executors.newSingleThreadExecutor()
創(chuàng)建一個單線程化的executor,它只創(chuàng)建唯一的worker線程來執(zhí)行任務(wù)
只有一個核心線程,保證所有的任務(wù)都在一個線程中順序執(zhí)行,意義在于不需要處理線程同步的問題。
一般用于執(zhí)行后臺耗時任務(wù),當任務(wù)執(zhí)行完成會自動停止;同時由于它是一個服務(wù),優(yōu)先級要遠遠高于線程,更不容易被系統(tǒng)殺死,因此比較適合執(zhí)行一些高優(yōu)先級的后臺任務(wù)。
使用步驟:創(chuàng)建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執(zhí)行耗時任務(wù)
原理:在源碼實現(xiàn)上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結(jié)束后會調(diào)用IntentService的stopSelf(int startId)方法嘗試停止服務(wù)。
IntentService的內(nèi)部是通過消息的方式請求HandlerThread執(zhí)行任務(wù),HandlerThread內(nèi)部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執(zhí)行后臺任務(wù)的
(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個工作線程(非UI線程)+任務(wù)的等待隊列的形式,優(yōu)點是不會有堵塞,減少了對性能的消耗,缺點是不能同時進行多個任務(wù)的處理,需要等待進行處理。處理效率低,可以當成一個輕量級的線程池來用)
傳統(tǒng)的多線程是通過繼承Thread類及實現(xiàn)Runnable接口來實現(xiàn)的,每次創(chuàng)建及銷毀線程都會消耗資源、響應速度慢,且線程缺乏統(tǒng)一管理,容易出現(xiàn)阻塞的情況,針對以上缺點,線程池就出現(xiàn)了。
線程池是一個創(chuàng)建使用線程并能保存使用過的線程以達到復用的對象,簡單的說就是一塊緩存了一定數(shù)量線程的區(qū)域。
1.復用線程:線程執(zhí)行完不會立刻退出,繼續(xù)執(zhí)行其他線程;
2.管理線程:統(tǒng)一分配、管理、控制最大并發(fā)數(shù);
1.降低因頻繁創(chuàng)建銷毀線程帶來的性能開銷,復用緩存在線程池中的線程;
2.提高線程執(zhí)行效率響應速度,復用線程:響應速度;管理線程:優(yōu)化線程執(zhí)行順序,避免大量線程搶占資源導致阻塞現(xiàn)象;
3.提高對線程的管理度;
線程池的使用也比較簡單,流程如下:
接下來通過源碼來介紹一下ThreadPoolExecutor內(nèi)部實現(xiàn)及工作原理。
線程池的最終實現(xiàn)類是ThreadPoolExecutor,通過實現(xiàn)可以一步一步的看到,父接口為Executor:
其他的繼承及實現(xiàn)關(guān)系就不一一列舉了,直接通過以下圖來看一下:
從構(gòu)造方法開始看:
通過以上可以看到,在創(chuàng)建ThreadPoolExecutor時,對傳入的參數(shù)是有要求的:corePoolSize不能小于0;maximumPoolSize需要大于0,且需要大于等于corePoolSize;keepAliveTime大于0;workQueue、threadFactory都不能為null。
在創(chuàng)建完后就需要執(zhí)行Runnable了,看以下execute()方法:
在execute()內(nèi)部主要執(zhí)行的邏輯如下:
分析點1:如果當前線程數(shù)未超過核心線程數(shù),則將runnable作為參數(shù)執(zhí)行addWorker(),true表示核心線程,false表示非核心線程;
分析點2:核心線程滿了,如果線程池處于運行狀態(tài)則往workQueue隊列中添加任務(wù),接下來判斷是否需要拒絕或者執(zhí)行addWorker();
分析點3:以上都不滿足時 [corePoolSize=0且沒有運行的線程,或workQueue已經(jīng)滿了] ,執(zhí)行addWorker()添加runnable,失敗則執(zhí)行拒絕策略;
總結(jié)一下:線程池對線程創(chuàng)建的管理,流程圖如下:
在執(zhí)行addWorker時,主要做了以下兩件事:
分析點1:將runnable作為參數(shù)創(chuàng)建Worker對象w,然后獲取w內(nèi)部的變量thread;
分析點2:調(diào)用start()來啟動thread;
在addWorker()內(nèi)部會將runnable作為參數(shù)傳給Worker,然后從Worker內(nèi)部讀取變量thread,看一下Worker類的實現(xiàn):
Worker實現(xiàn)了Runnable接口,在Worker內(nèi)部,進行了賦值及創(chuàng)建操作,先將execute()時傳入的runnable賦值給內(nèi)部變量firstTask,然后通過ThreadFactory.newThread(this)創(chuàng)建Thread,上面講到在addWorker內(nèi)部執(zhí)行t.start()后,會執(zhí)行到Worker內(nèi)部的run()方法,接著會執(zhí)行runWorker(this),一起看一下:
前面可以看到,runWorker是執(zhí)行在子線程內(nèi)部,主要執(zhí)行了三件事:
分析1:獲取當前線程,當執(zhí)行shutdown()時需要將線程interrupt(),接下來從Worker內(nèi)部取到firstTask,即execute傳入的runnable,接下來會執(zhí)行;
分析2:while循環(huán),task不空直接執(zhí)行;否則執(zhí)行g(shù)etTask()去獲取,不為空直接執(zhí)行;
分析3:對有效的task執(zhí)行run(),由于是在子線程中執(zhí)行,因此直接run()即可,不需要start();
前面看到,在while內(nèi)部有執(zhí)行g(shù)etTask(),一起看一下:
getTask()是從workQueue內(nèi)部獲取接下來需要執(zhí)行的runnable,內(nèi)部主要做了兩件事:
分析1:先獲取到當前正在執(zhí)行工作的線程數(shù)量wc,通過判斷allowCoreThreadTimeOut[在創(chuàng)建ThreadPoolExecutor時可以進行設(shè)置]及wc corePoolSize來確定timed值;
分析2:通過timed值來決定執(zhí)行poll()或者take(),如果WorkQueue中有未執(zhí)行的線程時,兩者作用是相同的,立刻返回線程;如果WorkQueue中沒有線程時,poll()有超時返回,take()會一直阻塞;如果allowCoreThreadTimeOut為true,則核心線程在超時時間沒有使用的話,是需要退出的;wc corePoolSize時,非核心線程在超時時間沒有使用的話,是需要退出的;
allowCoreThreadTimeOut是可以通過以下方式進行設(shè)置的:
如果沒有進行設(shè)置,那么corePoolSize數(shù)量的核心線程會一直存在。
總結(jié)一下:ThreadPoolExecutor內(nèi)部的核心線程如何確保一直存在,不退出?
上面分析已經(jīng)回答了這個問題,每個線程在執(zhí)行時會執(zhí)行runWorker(),而在runWorker()內(nèi)部有while()循環(huán)會判斷getTask(),在getTask()內(nèi)部會對當前執(zhí)行的線程數(shù)量及allowCoreThreadTimeOut進行實時判斷,如果工作數(shù)量大于corePoolSize且workQueue中沒有未執(zhí)行的線程時,會執(zhí)行poll()超時退出;如果工作數(shù)量不大于corePoolSize且workQueue中沒有未執(zhí)行的線程時,會執(zhí)行take()進行阻塞,確保有corePoolSize數(shù)量的線程阻塞在runWorker()內(nèi)部的while()循環(huán)不退出。
如果需要關(guān)閉線程池,需要如何操作呢,看一下shutdown()方法:
以上可以看到,關(guān)閉線程池的原理:a. 遍歷線程池中的所有工作線程;b. 逐個調(diào)用線程的interrupt()中斷線程(注:無法響應中斷的任務(wù)可能永遠無法終止)
也可調(diào)用shutdownNow()來關(guān)閉線程池,二者區(qū)別:
shutdown():設(shè)置線程池的狀態(tài)為SHUTDOWN,然后中斷所有沒有正在執(zhí)行任務(wù)的線程;
shutdownNow():設(shè)置線程池的狀態(tài)為STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線程,并返回等待執(zhí)行任務(wù)的列表;
使用建議:一般調(diào)用shutdown()關(guān)閉線程池;若任務(wù)不一定要執(zhí)行完,則調(diào)用shutdownNow();
總結(jié)一下:ThreadPoolExecutor在執(zhí)行execute()及shutdown()時的調(diào)用關(guān)系,流程圖如下:
線程池可以通過Executors來進行不同類型的創(chuàng)建,具體分為四種不同的類型,如下:
可緩存線程池:不固定線程數(shù)量,且支持最大為Integer.MAX_VALUE的線程數(shù)量:
1、線程數(shù)無限制
2、有空閑線程則復用空閑線程,若無空閑線程則新建線程
3、一定程度上減少頻繁創(chuàng)建/銷毀線程,減少系統(tǒng)開銷
固定線程數(shù)量的線程池:定長線程池
1、可控制線程最大并發(fā)數(shù)(同時執(zhí)行的線程數(shù))
2、超出的線程會在隊列中等待。
單線程化的線程池:可以理解為線程數(shù)量為1的FixedThreadPool
1、有且僅有一個工作線程執(zhí)行任務(wù)
2、所有任務(wù)按照指定順序執(zhí)行,即遵循隊列的入隊出隊規(guī)則
定時以指定周期循環(huán)執(zhí)行任務(wù)
一般來說,等待隊列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 與 SynchronousQueue 。
假設(shè)向線程池提交任務(wù)時,核心線程都被占用的情況下:
ArrayBlockingQueue :基于數(shù)組的阻塞隊列,初始化需要指定固定大小。
當使用此隊列時,向線程池提交任務(wù),會首先加入到等待隊列中,當?shù)却犃袧M了之后,再次提交任務(wù),嘗試加入隊列就會失敗,這時就會檢查如果當前線程池中的線程數(shù)未達到最大線程,則會新建線程執(zhí)行新提交的任務(wù)。所以最終可能出現(xiàn)后提交的任務(wù)先執(zhí)行,而先提交的任務(wù)一直在等待。
LinkedBlockingQueue :基于鏈表實現(xiàn)的阻塞隊列,初始化可以指定大小,也可以不指定。
當指定大小后,行為就和 ArrayBlockingQueue一致。而如果未指定大小,則會使用默認的 Integer.MAX_VALUE 作為隊列大小。這時候就會出現(xiàn)線程池的最大線程數(shù)參數(shù)無用,因為無論如何,向線程池提交任務(wù)加入等待隊列都會成功。最終意味著所有任務(wù)都是在核心線程執(zhí)行。如果核心線程一直被占,那就一直等待。
SynchronousQueue :無容量的隊列。
使用此隊列意味著希望獲得最大并發(fā)量。因為無論如何,向線程池提交任務(wù),往隊列提交任務(wù)都會失敗。而失敗后如果沒有空閑的非核心線程,就會檢查如果當前線程池中的線程數(shù)未達到最大線程,則會新建線程執(zhí)行新提交的任務(wù)。完全沒有任何等待,唯一制約它的就是最大線程數(shù)的個數(shù)。因此一般配合Integer.MAX_VALUE就實現(xiàn)了真正的無等待。
但是需要注意的是, 進程的內(nèi)存是存在限制的,而每一個線程都需要分配一定的內(nèi)存。所以線程并不能無限個。
GlobalThreadPools.java:
調(diào)用:
線程池
線程池概念來源于Java中的Executor,它是一個接口,真正的實現(xiàn)為ThreadPoolExecutor。ThreadPoolExecutor提供了一系列參數(shù)來配置線程池。
優(yōu)點
1:重用線程池中的線程,線程在執(zhí)行完任務(wù)后不會立刻銷毀,而會等待另外的任務(wù),這樣就不會頻繁地創(chuàng)建、銷毀線程和調(diào)用GC。。
2:有效控制線程池的最大并發(fā)數(shù),避免大量線程搶占資源出現(xiàn)的問題。
3:對多個線程進行統(tǒng)一地管理,可提供定時執(zhí)行及指定間隔循環(huán)執(zhí)行的功能。
ThreadPoolExecutor 有多個重載方法,但最終都調(diào)用了這個構(gòu)造方法
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueueRunnable workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
參數(shù):
corePoolSize:線程池中核心線程的數(shù)量;為了內(nèi)存優(yōu)化,在線程池維護了幾個重要的線程,不達到一定條件不開辟其余線程
maximumPoolSize :線程池中最大線程數(shù)量:這個數(shù)量是包括核心線程的,當線程池中的正在執(zhí)行的線程池達到了這個數(shù)字,再提交線程如果你不做特殊處理將會拋出異常
keepAliveTime:非核心線程的超時時長;當線程池中的非核心線程閑置時間超過這個值代表的時間后,將會被回收;同時如果調(diào)用ThreadPoolExecutor.allowCoreThreadTimeOut(true),那么核心線程也會符合這個設(shè)置
unit:keepAliveTime值的單位,可以是時分秒等
workQueue:存放待執(zhí)行的線程;你通過execute方法提交線程,但是這些線程還沒達到執(zhí)行條件,那么就會保存在這個隊列里
threadFactory:創(chuàng)建線程池的工廠;在這個工廠里,我們可以指定線程的一些信息
handler:線程提交拒絕策略;通常是線程池中的正在執(zhí)行的線程數(shù)量已經(jīng)達到了最大線程數(shù)或線程池關(guān)閉,如果不傳,默認是拋出一個RejectedExecutionException,所以最好傳下
推薦使用 Executors 的工廠方法來創(chuàng)建線程池,通過直接或間接的配置 ThreadPoolExecutor 的參數(shù)來構(gòu)建線程池,常用的線程池有如下 4 種,newFixedThreadPool ,newCachedThreadPool,
newScheduledThreadPool 和 newSingleThreadExecutor。
ThreadPoolExecutor 執(zhí)行任務(wù)時大致遵循如下流程:
1.如果線程池中的線程數(shù)未達到核心線程數(shù),則會立馬啟用一個核心線程去執(zhí)行。
2.如果線程池中的線程數(shù)已經(jīng)達到核心線程數(shù),且任務(wù)隊列workQueue未滿,則將新線程放入workQueue中等待執(zhí)行。
3.如果線程池中的線程數(shù)已經(jīng)達到核心線程數(shù)但未超過線程池規(guī)定最大值,且workQueue已滿,則開啟一個非核心線程來執(zhí)行任務(wù)。
4.如果線程池中的線程數(shù)已經(jīng)超過線程池規(guī)定最大值,則拒絕執(zhí)行該任務(wù),采取飽和策略,并拋出RejectedExecutionException異常。
線程池大小:(N為CPU數(shù)量)
如果是CPU密集型應用,則線程池大小設(shè)置為N+1
如果是IO密集型應用,則線程池大小設(shè)置為2N+1
I/O密集型
指的是系統(tǒng)的CPU效能相對硬盤/內(nèi)存的效能要好,大部分的狀況是 CPU 在等 I/O (硬盤/內(nèi)存) 的讀/寫, CPU Loading 不高。
CPU密集型
指的是系統(tǒng)的 硬盤/內(nèi)存 效能 相對 CPU 的效能 要好,大部分的狀況是 CPU Loading 100%,CPU 要讀/寫 I/O (硬盤/內(nèi)存),I/O在很短的時間就可以完成,而 CPU 還有許多運算要處理,CPU Loading 很高。
獲取CPU數(shù)量的方法為:
Runtime.getRuntime().availableProcessors();
摘自:
在Android中有主線程和子線程的區(qū)分。主線程又稱為UI線程,主要是處理一些和界面相關(guān)的事情,而子線程主要是用于處理一些耗時比較大的一些任務(wù),例如一些網(wǎng)絡(luò)操作,IO請求等。如果在主線程中處理這些耗時的任務(wù),則有可能會出現(xiàn)ANR現(xiàn)象(App直接卡死)。
線程池,從名字的表明含義上我們知道線程池就是包含線程的一個池子,它起到新建線程、管理線程、調(diào)度線程等作用。
既然Android中已經(jīng)有了線程的概念,那么為什么需要使用線程池呢?我們從兩個方面給出使用線程池的原因。
在Android中線程池就是ThreadPoolExecutor對象。我們先來看一下ThreadPoolExecutor的構(gòu)造函數(shù)。
我們分別說一下當前的幾個參數(shù)的含義:
第一個參數(shù)corePoolSize為 核心線程數(shù) ,也就是說線程池中至少有這么多的線程,即使存在的這些線程沒有執(zhí)行任務(wù)。但是有一個例外就是,如果在線程池中設(shè)置了allowCoreThreadTimeOut為true,那么在 超時時間(keepAliveTime) 到達后核心線程也會被銷毀。
第二個參數(shù)maximumPoolSize為 線程池中的最大線程數(shù) 。當活動線程數(shù)達到這個數(shù)后,后續(xù)添加的新任務(wù)會被阻塞。
第三個參數(shù)keepAliveTime為 線程的?;顣r間 ,就是說如果線程池中有多于核心線程數(shù)的線程,那么在線程沒有任務(wù)的那一刻起開始計時,如果超過了keepAliveTime,還沒有新的任務(wù)過來,則該線程就要被銷毀。同時如果設(shè)置了allowCoreThreadTimeOut為true,該時間也就是上面第一條所說的 超時時間 。
第四個參數(shù)unit為 第三個參數(shù)的計時單位 ,有毫秒、秒等。
第五個參數(shù)workQueue為 線程池中的任務(wù)隊列 ,該隊列持有由execute方法傳遞過來的Runnable對象(Runnable對象就是一個任務(wù))。這個任務(wù)隊列的類型是BlockQueue類型,也就是阻塞隊列,當隊列的任務(wù)數(shù)為0時,取任務(wù)的操作會被阻塞;當隊列的任務(wù)數(shù)滿了(活動線程達到了最大線程數(shù)),添加操作就會阻塞。
第六個參數(shù)threadFactory為 線程工廠 ,當線程池需要創(chuàng)建一個新線程時,使用線程工廠來給線程池提供一個線程。
第七個參數(shù)handler為 拒絕策略 ,當線程池使用有界隊列時(也就是第五個參數(shù)),如果隊列滿了,任務(wù)添加到線程池的時候的一個拒絕策略。
可以看到FixedThreadPool的構(gòu)建調(diào)用了ThreadPoolExecutor的構(gòu)造函數(shù)。從上面的調(diào)用中可以看出FixedThreadPool的幾個特點:
可以看到CacheThreadPool的構(gòu)建調(diào)用了ThreadPoolExecutor的構(gòu)造函數(shù)。從上面的調(diào)用中可以看出CacheThreadPool的幾個特點:
可以看到ScheduledThreadPoolExecutor的構(gòu)建調(diào)用了ThreadPoolExecutor的構(gòu)造函數(shù)。從上面的調(diào)用中可以看出ScheduledThreadPoolExecutor的幾個特點:
可以看到SingleThreadExecutor的構(gòu)建調(diào)用了ThreadPoolExecutor的構(gòu)造函數(shù)。從上面的調(diào)用中可以看出SingleThreadExecutor的幾個特點:
分享題目:android線程池,Android線程池面試題
當前地址:http://chinadenli.net/article40/dsdideo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應網(wǎng)站、網(wǎng)站內(nèi)鏈、標簽優(yōu)化、服務(wù)器托管、網(wǎng)頁設(shè)計公司、網(wǎng)站營銷
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)