問題:請講下java中的執行緒池
分析:在面試中經常問到執行緒池的問題,要掌握其基本概念,使用方法,注意事項等,引申下tomcat中預設的執行緒數是多少
回答要點:
主要從以下幾點去考慮,
1、為什麼要使用執行緒池
2、執行緒池的基本引數
3、為什麼不使用java提供的執行緒池,而是使用自己建立
4、如何設定執行緒數大小;
5、執行緒池在tomcat中的使用;
為什麼要使用執行緒池
在日常的開發過程中,經常要用到多執行緒,那麼為什麼不直接新建一個執行緒,而是選擇使用執行緒池那,因為執行緒的建立要消耗系統資源,佔用CPU的時間,所以考慮使用執行緒池;
執行緒池的基本引數
Java提供了執行緒池類ThreadPoolExecutor,該類是執行緒池的基類,有以下引數
corePoolSize 核心執行緒數
maximumPoolSize 最大執行緒數
keepAliveTime 執行緒數超過核心執行緒數後,多餘的執行緒的空閒時間
unit 上面的引數的單位
workQueue 阻塞佇列
threadFactory 建立執行緒的工廠
handler 拒絕策略
一個任務被提交到執行緒池的過程:
從上面的流程圖中可以引申出以下幾個問題,核心執行緒數要怎麼設定;阻塞佇列有幾種;拒絕策略有幾種;
先看阻塞佇列及決策策略
阻塞佇列
常用的阻塞佇列有ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、priorityBlockingQueue
ArrayBlockingQueue 底層使用陣列+ReeTrantLock實現,既然是陣列實現那麼必然就要指定陣列的長度
LinkedBlockingQueue 使用單連結串列實現,最大長度為Integer.MAX_VALUE
SynchronousQueue 要將任務放入SynchronousQueue中必須有一個執行緒在等待消費該任務,如果沒有執行緒在等待,那麼執行緒池中執行緒數小於最大執行緒數就會建立一個執行緒,否則會執行拒絕策略
PriorityBlockingQueue 具有優先順序的阻塞佇列
拒絕策略
ThreadPoolExecutor實現了4中拒絕策略,CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy
CallerRunsPolicy 呼叫者來執行該任務;
AbortPolicy 丟擲異常,開發者可以捕獲該異常,預設的策略;
DiscardPolicy 直接丟棄,什麼也不做;
DiscardOldestPolicy 丟棄佇列中最老的任務,就是最先入隊的任務,也即將要被執行的任務;
java提供的執行緒池
Java的Exectors類提供了一些執行緒池的方法供開發者來用,但是最好不用Java提供的,下面看有哪些以及為什麼不建議使用
newFixedThreadPool() 固定執行緒數的執行緒池,核心執行緒數=最大執行緒數,使用LinkedBlockingQueue,拒絕策略是預設的AbortPolicy;適用於為了滿足資源管理的要求,而限制執行緒數量,適用於負載較重的機器
newSingleThreadExecutor() 只有一個執行緒的執行緒池,核心執行緒數=最大執行緒數=1,使用LinkedBlockingQueue,拒絕策略是預設的AbortPolicy;適用於順序執行各個任務的場景
newCachedThreadPool() 按需建立新的執行緒池,核心執行緒數=0,最大執行緒數為Integer.MAX_VALUE,阻塞佇列為SynchronousQueue,拒絕策略是預設的AbortPolicy,執行緒池可以無限擴充套件,當任務多時建立許多執行緒,任務少時,自動清空執行緒;適應於執行短期非同步任務,或者負載較輕的機器
newScheduledThreadPool() 建立一個延時或定時的執行緒池,最大執行緒數為Integer.MAX_VALUE,阻塞佇列為DelayedWorkQueue
如何設定執行緒池中執行緒的數量
要想設定合理的執行緒數,需要區分任務是計算(CPU)密集型還是IO密集型
計算密集型 針對計算密集型一般設定為CPU核數+1比較合理,因為是計算密集型,那麼計算就要用CPU,設定為CPU的核數可以充分利用CPU的優勢,至於為什麼要加1,可以理解為計算密集型,也要有IO操作,加1是為了在等待IO的時候,充分利用CPU
IO密集型 對應IO密集型,也就是說該任務涉及很多的IO操作,比如讀寫磁碟,遠端RPC呼叫等,網上有很多數是設定為2*CPU核數+1,當然這也是可以的,不過下面這樣設定可能更能發揮CPU的效能,CPU數*CPU利用率*(任務等待時間/任務計算時間+1),假如有個8核機器,任務有100ms在計算,800ms在等待IO,CPU的利用率為100%的話,執行緒數=8*1*(800/100+1)=72,當然現實場景中CPU的利用率不可能飆到100%,還要具體場景具體分析;
執行緒池在tomcat中的使用
tomcat作為servlet伺服器,要處理請求,是為每個請求建立一個執行緒,那麼它的配置是在哪裡那,在tomcat的conf/server.xml檔案中
看上面有個Executor的配置例項,maxThreads的配置,看上圖中例子給出的值為150。其實tomcat7/8預設的執行緒池大小為200.
參考:https://joonwhee.blog.csdn.net/article/details/106609583