java面試一日一題:java線程池


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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM