java 執行緒池簡介
- 2019 年 10 月 25 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/qq_32534855/article/details/99608297
簡介
什麼是「池」 : 軟體中的「池」,可以理解為計劃經濟時代的工廠。 首先,作為工廠,你要管理好你生產的東西,老王從你工廠這裡拿走了一把斧頭,改天他不需要了,還回來,你可以把這把斧頭借給老趙; 其次,你又不能無限制的生產,畢竟在資源極度匱乏的時代,如果都被你拿去生產了,其他要用到資源的地方怎麼辦? 總結成兩點,「池」的作用: 復用已有資源 控制資源總量 資料庫連接池是這樣,執行緒池也是如此。 你一個任務過來了,我發現池子里有沒事幹並且還活著的執行緒,來,拿去用,我也不用費事給你創建一條執行緒了,要知道執行緒的創建和銷毀可都是麻煩事; 你一個任務過來了,我發現池子的執行緒都在忙,並且現在池子的執行緒已經太多了,再不限制下去就要記憶體溢出了,來,排隊去~
Java中常見的4種執行緒池:
1 FixedThreadPool 2 CachedThreadPool 3 ScheduledThreadPool 4 SingleThreadExecutor
FixedThreadPool: 固定執行緒數的執行緒池,可控制執行緒最大並發數,超出的執行緒會在隊列中等待。

這裡的執行緒數是固定的,每個執行緒都會從任務隊列中去取任務,由於這個取的動作是並發的,所以要求任務隊列具有執行緒安全的特性,所以通常會使用阻塞隊列來實現。
CachedThreadPool: 可快取執行緒池(特點: 無界執行緒池,具有自動回收多餘執行緒的功能)

在這種情況下,我們的執行緒數量並不是固定的,而且我們也沒有一個用來存儲已提交任務的隊列;相反,這種執行緒池用有一個同步隊列(synchronous queue),它只能存儲1個Task。每當我們提交了一個任務給執行緒池,這個任務就會被放到這個隊列中。此時,執行緒池會在已經創建的所有執行緒中去尋找空閑的執行緒,並把這一個任務交給這個空閑的執行緒去執行。如果執行緒池沒能找到一個空閑的執行緒,說明所有的執行緒都在工作,那麼它就會新建一個執行緒,並把這個任務交給這個剛剛創建好的執行緒去執行,這樣就達到了動態增加執行緒數量的目的。
ScheduledThreadPool 支援定時及周期性任務執行的執行緒池。
這種執行緒池是專門服務於需要延遲或周期執行任務的場景,例如我們需要每10秒進行一次安全檢查。 ScheduledThreadPool主要有3種執行任務的方法: 1. service.schedule 延遲且單次執行,例如10秒後執行,總共只執行一次 2. service.scheduleAtFixedRate 每間隔固定時間執行一次,例如每10秒執行一次 3. service.scheduleAtFixedDelay 在上一個任務執行後,間隔固定時間再次執行。例如:每個Task需要執行5分鐘,那麼我們可以設定在這個Task直接結束後,等待1分鐘再執行下一次的任務,所以最終的效果就是每6分鐘該任務會被執行一次。 scheduleAtFixedRate和scheduleAtFixedDelay的區別在於,scheduleAtFixedRate是以任務開始執行的時間為起點,開始計時,而scheduleAtFixedDelay是以任務執行完畢為時間起點進行計時。
這裡用來存儲Task的queue是一個延遲隊列,延遲隊列的特點是:不是先進先出,而是會按照延遲時間的長短來排序,下一個即將執行的任務會排到隊列的最前面。我們來舉個例子:例如我們往這個隊列中,放一個延遲10分鐘執行的任務,然後再放一個延遲10秒鐘執行的任務。通常而言,如果不是延遲隊列而是普通隊列,那麼按照先進先出的排列規則,也就是第一個放置的會排在最前面,也就是延遲10分鐘執行的那個任務會放在最前面,但是由於我們此時使用的是延遲隊列,延遲隊列在排放各個任務的位置的時候,會根據延遲時間的長短來排放。所以。我們第二個放置的延遲10秒鐘執行的那個任務,反而會排在延遲10分鐘的任務的前面,因為它的執行時間更早。
SingleThreadExecutor 單執行緒的執行緒池:它只會用唯一的工作執行緒來執行任務,它的原理和FixedThreadPool是一樣的,但是此時的執行緒數量被設置為了1。這裡的這一個執行緒,會不停地從任務隊列里取任務,然後執行。如果執行緒在執行任務的時候,遇到了異常導致執行緒執行中斷,那麼執行緒池會重新創建一個執行緒繼續執行後續的任務,而不會永遠地中斷執行任務。
使用場景:目的是保證所有任務按照提交任務的順序執行。例如我們想要讓第二個任務必須在第一個任務之後執行,同理,或者我們希望讓任務三在任務二之後執行,這種場景下就需要用到SingleThreadExecutor。因為執行任務的執行緒只有一個,所以我們可以保證執行的順序,而之前那幾種執行緒池在執行的時候,由於有多個執行緒同時執行,所以我們不能保證各個任務之間的執行順序。
以上4種執行緒池的構造函數的參數: 其中fixedThreadPool的keepAliveTime是0秒,這裡的0代表永久,也就是fixedThreadPool不會kill任何一個idle的執行緒,即便該執行緒無事可做(不執行Task)。 newCachedThreadPool的參數指定了corePoolSize為0,所以CachedThreadPool在最開始的時候並不會創建執行緒,直到有Task進來,需要執行緒工作的時候才會創建執行緒。而可以看出CachedThreadPool的maxPoolSize的值是Integer.MAX_VALUE,這可能會創建數量非常多的執行緒,甚至導致OOM。 ScheduledThreadPool和SingleThreadPool也是同理。
