執行緒池使用總結
執行緒池使用總結
Excutors工廠類
為了更好的控制更多的多執行緒,JDK提供返回一個固定數量的執行緒池。
方法:
- newFixedThreadPool()方法:
改方法返回一個固定數量的執行緒池,改方法的執行緒數,始終不變,當一個任務提交時,若執行緒池空閒,則立即執行,若沒有,則會被暫緩在一個任務佇列中等待有空閒的執行緒去執行。 - newSingleThreadPool()方法
建立一個單例的執行緒池,若空閒則執行,若沒有空閒執行緒則暫緩在任務佇列中 - newCachedThreadPool()方法
返回一個可根據實際情況調整執行緒個數的執行緒池,不限制最大執行緒數量,若有任務,則建立執行緒,若無任務則不建立執行緒,如果沒有任務則執行緒會在60s後自動回收。 - newScheduledThreadPool()方法:該方法返回一個ScheduledExcutorService物件,但該執行緒池可以指定執行緒的數量。
自定義執行緒池-ThreadPoolExecutors
- 自定義執行緒池:ThreadPoolExecutor
執行緒池相關引數的配置
ThreadPoolExecutor(int corePoolSize, //核心執行緒數,執行緒初始化就會被建立 int maximumPoolSize, //執行緒池最大執行緒數,無界佇列時,不起作用 long keepAliveTime, //執行緒的存活時間 TimeUnit unit, //時間的單位 BlockingQueue<Runnable> workQueue, //阻塞佇列,使用無界佇列時,拒絕策略無用 ThreadFactory threadFactory,//theadFactory 執行緒工廠,用於獲取一個新的執行緒,然後把該執行緒投遞到執行緒池裡面去 RejectedExecutionHandler handler) //拒絕策略
1.當設定為有界佇列時:
a 若有新的任務需要執行,如果執行緒實際數小於coreThread,則先建立執行緒
b.若大於coreSize,則會加入任務佇列
c.若佇列已滿,則在不大於maxinumPoolsize的情況下建立新的執行緒
d.若執行緒數不大於maxinumPoolSize會執行拒絕策略
2.當為無界佇列時
a.maximumPoolSize不起作用,也沒有拒絕策略
b.若有新的任務需要執行,如果執行緒實際數小於coreThread,則先建立執行緒
c.若大於coreSize,則會加入任務佇列,同時建立新的執行緒。
如何使用好執行緒池?
- 執行緒個數大小的設定
- 執行緒池相關引數的配置
- 利用Hook嵌入你的行為
- 執行緒池的關閉
執行緒池數量的設定
計算機密集型
應用需要非常多的CPU計算資源,避免過多的執行緒上下文切換
執行緒數 = CPU核數+1,已可以設定為CPU核數*2,還要看JDK的版本以及CPU配置(伺服器的CPU有超執行緒)
IO密集型
Web應用,涉及到大量的網路傳輸,不僅如此,與資料庫,與快取間的互動也涉及到IO,一旦發生IO,執行緒就會處於等待狀態,當IO結束後,資料準備好後,執行緒才會繼續執行。對於IO密集型的應用,我們可以多設定執行緒池中執行緒的數量,這樣就能讓等待IO的這段時間內,執行緒可以去做其它事,提高併發處理效率。執行緒上下文切換數有代價的
執行緒數 = CPU核數/(1-阻塞係數) 這個阻塞係數一般為0.8~0.9之間。
套用公司:對於雙核CPU來說,比較理想的執行緒數就是20,當然這不是絕對的,需要根據實際情況以及實際業務來調整:final int poolSIze = (int)(copCore/(1-0.9))
執行緒池相關引數如何配置?
- 高壓線:
- 我們使用執行緒池的時候都不要選擇沒有上限限制的配置項
- 第一 我們不要去使用沒有上限的執行緒池和設定無界佇列!
- 比如,newCachedThreadPool的設定與無界佇列因為某些不可預期的情況,執行緒池會出現系統異常,導致執行緒暴增的情況或者任務佇列或者任務佇列不斷膨脹,記憶體耗盡導致系統崩潰。我們建議自定義執行緒池來避免改問題,這是在使用執行緒池的首要選擇。小心無大錯,千萬別過度自信。
- 第二 合理設定執行緒數量、和執行緒空閒回收時間,根據具體的任務執行週期和時間去設定,避免頻繁的回收和建立,雖然我們使用執行緒池的目的是為了提升系統性能和吞吐量,但是也要考慮下系統的穩定性,不然出現不可預期問題會很麻!
- 第三,根據實際場景,選擇適用於自己的拒絕策略。進行補償,不要亂用JDK支援的自動補償機制~儘量採用自定義的拒絕策略去進行兜底!
利用Hook去嵌入你的行為
- 利用Hook,留下執行緒池執行的執行軌跡
- ThreadPoolExcutor提供了protected型別可以被覆蓋的鉤子方法,執行使用者在執行任務之前或執行之後做一些事情。我們可以通過它來實現比如初始化ThreadLocal、收集統計資訊、如記錄日誌等操作,這類Hook如BeforeExcute和afterExecute。另外還有一個Hook可以用來在任務唄執行完的時候讓使用者插入邏輯,如reminated。
- Hook方法執行失敗,則內部的工作執行緒的執行將會失敗或者中斷。
關閉執行緒池
- 內容當執行緒池不在被引用並且工作執行緒數為0的時候,執行緒池將被終止。我們也可以呼叫shutdown來手動終止執行緒池。如果我們忘記呼叫shutdown,為了讓執行緒資源被釋放,我們還可以使用keepAliveTime和allowShutdownHook方法,手工去呼叫執行緒池的關閉方法!
- 最穩妥的方式是使用虛擬機器Runtime.getRuntime().addShutdownHook方法,手動去呼叫執行緒池關閉方法。