淺聊一下Java多線程:線程池

前言:當(dāng)我們線程創(chuàng)建過多時(shí),容易引發(fā)內(nèi)存溢出,這時(shí)我們?nèi)绾谓鉀Q這個(gè)問題呢?

一、什么是線程池

顧名思義,線程池就是一個(gè)用來裝線程的池子(容器)。首先需要?jiǎng)?chuàng)建若干個(gè)可執(zhí)行的線程放入一個(gè)池中,有任務(wù)需要處理時(shí),會(huì)提交到線程池中的任務(wù)隊(duì)列,處理完之后線程并不會(huì)被銷毀,而是仍然在線程池中等待下一個(gè)任務(wù)。

二、線程池原理詳解

線程池原理圖

首先需要?jiǎng)?chuàng)建一個(gè)線程池,然后需要?jiǎng)?chuàng)建若干個(gè)可執(zhí)行的線程放入一個(gè)池中(Thread1-5),但是只開啟一部分默認(rèn)的核心線程(例如Thread1-3),接下來有任務(wù)進(jìn)入并且假設(shè)都長時(shí)間持續(xù)占有線程時(shí),當(dāng)只有幾個(gè)(這里如果是小于等于三個(gè))任務(wù)時(shí),會(huì)按順序分配到三個(gè)核心線程中,如果大于三個(gè)則會(huì)進(jìn)入到任務(wù)隊(duì)列(workQueue,Task4-7)中等待,如果任務(wù)超過了workQueue的最大容納量,則創(chuàng)建新的線程(Thread4-5),并將workQueue中的任務(wù)按順序分別到線程中,Task8-9進(jìn)入workQueue,如果還有Task加入,那么調(diào)用拒絕策略方法,防止Task進(jìn)入;如果線程Thread4-5執(zhí)行完任務(wù)后在一定時(shí)間內(nèi)沒有任務(wù)進(jìn)入,則會(huì)被回收。

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

因此,從上面的分析來看,對比不使用線程池的情況(即創(chuàng)建線程對象、執(zhí)行任務(wù)、釋放線程對象),線程池具有以下優(yōu)點(diǎn):

  • 降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的消耗。(前面的Task先執(zhí)行完后后面的Task可以復(fù)用前面的線程)
  • 提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線程創(chuàng)建就能立即執(zhí)行。(提前創(chuàng)建好核心線程Thread1-3)
  • 提高線程的可管理性。線程是稀缺資源,如果無限制的創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

四、線程池的參數(shù)含義

首先,我們來看源碼:

   Executor executor = new ThreadPoolExecutor( 
                                              CORE_POOL_SIZE,
                                              MAXIMUM_POOL_SIZE,
                                              KEEP_ALIVE,
                                              TimeUnit.SECONDS, 
                                              sPoolWorkQueue,
                                              sThreadFactory 
                                               );
    public ThreadPoolExecutor (int corePoolSize,
                               int maximumPoolSize,
                               long keepAliveTime,
                               TimeUnit unit,
                               BlockingQueue<Runnable workQueue>,
                               ThreadFactory threadFactory )
  • corePoolSize:核心線程數(shù)。默認(rèn)情況下,核心線程會(huì)一直存活,但是當(dāng)將 allowCoreThreadTimeout 設(shè)置為 true 時(shí),核心線程也會(huì)超時(shí)回收。
  • maximumPoolSize:線程池所能容納的最大線程數(shù)。當(dāng)活躍線程數(shù)達(dá)到該數(shù)值后,后續(xù)的新任務(wù)將會(huì)阻塞。
  • keepAliveTime:線程閑置超時(shí)時(shí)長。如果超過該時(shí)長,非核心線程就會(huì)被回收。
  • unit:指定 keepAliveTime 參數(shù)的時(shí)間單位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
  • workQueue:任務(wù)隊(duì)列。通過線程池的 execute() 方法提交的 Runnable 對象將存儲(chǔ)在該參數(shù)中。其采用阻塞隊(duì)列實(shí)現(xiàn)。
  • threadFactory(可選):線程工廠。用于指定為線程池創(chuàng)建新線程的方式。
  • handler(可選):拒絕策略。當(dāng)達(dá)到最大線程數(shù)時(shí)需要執(zhí)行的飽和策略。

五、線程池的使用流程

// 創(chuàng)建線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
                                             MAXIMUM_POOL_SIZE,
                                             KEEP_ALIVE,
                                             TimeUnit.SECONDS,
                                             sPoolWorkQueue,
                                             sThreadFactory);
// 向線程池提交任務(wù)
threadPool.execute(new Runnable() {
    @Override
    public void run() {
        ... // 線程執(zhí)行的任務(wù)
    }
});
// 關(guān)閉線程池
threadPool.shutdown(); // 設(shè)置線程池的狀態(tài)為SHUTDOWN,然后中斷所有沒有正在執(zhí)行任務(wù)的線程
threadPool.shutdownNow(); // 設(shè)置線程池的狀態(tài)為 STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線程,并返回等待執(zhí)行任務(wù)的列表

六、常見線程池

  1. 定長線程池(FixedThreadPool):只有核心線程,線程數(shù)量固定,執(zhí)行完立即回收,任務(wù)隊(duì)列為鏈表結(jié)構(gòu)的有界隊(duì)列。
  2. 定時(shí)線程池(ScheduledThreadPool):核心線程數(shù)量固定,非核心線程數(shù)量無限,執(zhí)行完閑置 10ms 后回收,任務(wù)隊(duì)列為延時(shí)阻塞隊(duì)列。
  3. 可緩存線程池(CachedThreadPool):無核心線程,非核心線程數(shù)量無限,執(zhí)行完閑置 60s 后回收,任務(wù)隊(duì)列為不存儲(chǔ)元素的阻塞隊(duì)列。
  4. 單線程化線程池(SingleThreadExecutor):只有 1 個(gè)核心線程,無非核心線程,執(zhí)行完立即回收,任務(wù)隊(duì)列為鏈表結(jié)構(gòu)的有界隊(duì)列。

七、拒絕策略

  1. AbortPolicy(默認(rèn)):丟棄任務(wù)并拋出 RejectedExecutionException 異常。
  2. CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。
  3. DiscardPolicy:丟棄任務(wù),但是不拋出異常??梢耘浜线@種模式進(jìn)行自定義的處理方式。
  4. DiscardOldestPolicy:丟棄隊(duì)列最早的未處理任務(wù),然后重新嘗試執(zhí)行任務(wù)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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