天天看點

線程池實作原理吐血總結

要了解實作原理,必須把線程池的幾個參數徹底搞懂,不要死記硬背

線程池參數

1、corePoolSize(必填):核心線程數。

2、maximumPoolSize(必填):最大線程數。

3、keepAliveTime(必填):線程空閑時長。如果超過該時長,非核心線程就會被回收。

4、unit(必填):指定keepAliveTime的時間機關。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。

5、workQueue(必填):任務隊列。通過線程池的execute()方法送出的Runnable對象将存儲在該隊列中。

6、threadFactory(可選):線程工廠。一般就用預設的。

7、handler(可選):拒絕政策。當線程數達到最大線程數時就要執行飽和政策。

說下核心線程數和最大線程數的差別

拒絕政策可選值

1、AbortPolicy(預設):放棄任務并抛出RejectedExecutionException異常。

2、CallerRunsPolicy:由調用線程處理該任務。

3、DiscardPolicy:放棄任務,但是不抛出異常。可以配合這種模式進行自定義的處理方式。

4、DiscardOldestPolicy:放棄隊列最早的未處理任務,然後重新嘗試執行任務。

線程池執行流程

上個流程圖,先試着自己看下能不能看懂

線程池實作原理吐血總結

簡短的總結下線程池執行流程:

1、一個任務送出到線程池後,如果目前的線程數沒達到核心線程數,則建立一個線程并且執行新任務,注意一點,這個新任務執行完後,該線程不會被銷毀;

2、如果達到了,則判斷任務隊列滿了沒,如果沒滿,則将任務放入任務隊列;

3、如果滿了,則判斷目前線程數量是否達到最大線程數,如果沒達到,則建立新線程來執行任務,注意,如果線程池中線程數量大于核心線程數,每當有線程超過了空閑時間,就會被銷毀,直到線程數量不大于核心線程數;

4、如果達到了最大線程數,并且任務隊列滿了,就會執行飽和政策;

四種現成的線程池

不想自己new線程池的話,可以用現成的

1、定長線程池(FixedThreadPool)

特點:隻有核心線程,線程數量固定,執行完立即回收,任務隊列為連結清單結構的有界隊列。

應用場景:控制線程最大并發數

2、定時線程池(ScheduledThreadPool )

特點:核心線程數量固定,非核心線程數量無限,執行完閑置10ms後回收,任務隊列為延時阻塞隊列。

應用場景:執行定時或周期性的任務。

3、可緩存線程池(CachedThreadPool)

特點:無核心線程,非核心線程數量無限,執行完閑置60s後回收,任務隊列為不存儲元素的阻塞隊列。

應用場景:執行大量、耗時少的任務。

4、單線程化線程池(SingleThreadExecutor)

特點:隻有1個核心線程,無非核心線程,執行完立即回收,任務隊列為連結清單結構的有界隊列。

應用場景:不适合并發但可能引起IO阻塞性及影響UI線程響應的操作,如資料庫操作、檔案操作等。

上述四個線程池雖然友善,但是阿裡巴巴規範明确說明不建議使用,因為可能會造成記憶體溢出,具體原因如下:

FixedThreadPool和SingleThreadExecutor:主要問題是堆積的請求處理隊列均采用LinkedBlockingQueue,可能會耗費非常大的記憶體,嚴重的直接導緻記憶體溢出。

CachedThreadPool和ScheduledThreadPool:主要問題是它們的最大線程數是Integer.MAX_VALUE,可能會建立數量非常多的線程,嚴重的直接導緻記憶體溢出。

ok我話說完