java面試一日一題:java執行緒池

迷茫中守候發表於2021-04-10

問題:請講下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

 

相關文章