java 一共含有四種線程池: newCachedThreadPool, newFixedThreadPool, newSingleThreadExecutor, newScheduledThreadPool。
newCachedThreadPool:顧名思義是一種可緩存的線程池, 線程池除了維護初始大小的線程外,當任務數量超出線程池大小時,便會新建線程, 而且當線程完成任務之后不會馬上銷毀,而是會保留一段時間(默認60s),這種極大的減少了線程創建和銷毀的資源消耗, 當這種線程池的弊端是 線程最大值過大, 如果用於高並發且任務較長場景,很容易將內存全部吃光。 所以使用於執行短期異步小任務,或者並發量不高的場景。
newFixedThreadPool :是基於無界隊列的線程池, 維護的線程數量是固定的,如果線程均在繁忙狀態,則新任務會放入無界隊列里。 適用於長期任務。 如果用於短期任務,任務數量 < 線程池數量時,性能不會跟newCachedThreadPool太大的區別,但是超出時, 因為是短期的, 所以任務會不斷的被放入隊列,又被取出, 時間間隔很短,並且過多的短期任務放入隊列中,回使得內存吃緊,當任務數量過多時會造成很大的資源浪費。
newSingleThreadExecutor:顧名思義是只有一個單線程的線程池,具體場景不太清晰, 按照線程含義來看,適用於需要按順序(FIFO, LIFO, 優先級)的執行任務的場景,以及thread confinement(變量只能由特定線程訪問)的要求。
newScheduleThreadPool :如果所有線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構。這個線程的應用場景就很容易知道了, 需要周期性執行的任務使用該線程池。
線程池任務執行流程:
當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。
當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉
備注:
一般如果線程池任務隊列采用LinkedBlockingQueue隊列的話,那么不會拒絕任何任務(因為隊列大小沒有限制),這種情況下,ThreadPoolExecutor最多僅會按照最小線程數來創建線程,也就是說線程池大小被忽略了。
如果線程池任務隊列采用ArrayBlockingQueue隊列的話,那么ThreadPoolExecutor將會采取一個非常負責的算法,比如假定線程池的最小線程數為4,最大為8所用的ArrayBlockingQueue最大為10。隨着任務到達並被放到隊列中,線程池中最多運行4個線程(即最小線程數)。即使隊列完全填滿,也就是說有10個處於等待狀態的任務,ThreadPoolExecutor也只會利用4個線程。如果隊列已滿,而又有新任務進來,此時才會啟動一個新線程,這里不會因為隊列已滿而拒接該任務,相反會啟動一個新線程。新線程會運行隊列中的第一個任務,為新來的任務騰出空間。
這個算法背后的理念是:該池大部分時間僅使用核心線程(4個),即使有適量的任務在隊列中等待運行。這時線程池就可以用作節流閥。如果擠壓的請求變得非常多,這時該池就會嘗試運行更多的線程來清理;這時第二個節流閥—最大線程數就起作用了。
ThreadPoolExecutor:
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; } //因為ctl以(1<<29)開始遞增,轉化為以0開始遞增的數字 例如 workerCOuntOf( (1<<29) +9 ) = 9;
private static int ctlOf(int rs, int wc) { return rs | wc; }
參考文章:https://www.cnblogs.com/sachen/p/7401959.html