java面試題之-線程池

什麼是線程池?

線程池是一種多線程處理形式,處理過程中將任務提交到線程池,任務的執行交由線程池來管理。

如果每個請求都創建一個線程去處理,那麼服務器的資源很快就會被耗盡,使用線程池可以減少創建和銷燬線程的次數,每個工作線程都可以被重複利用,可執行多個任務。

 

爲什麼要使用線程池?

創建線程和銷燬線程的花銷是比較大的,這些時間有可能比處理業務的時間還要長。這樣頻繁的創建線程和銷燬線程,再加上業務工作線程,消耗系統資源的時間,可能導致系統資源不足。(我們可以把創建和銷燬的線程的過程去掉)

 

線程池有什麼作用?

線程池作用就是限制系統中執行線程的數量。

1、提高效率 創建好一定數量的線程放在池中,等需要使用的時候就從池中拿一個,這要比需要的時候創建一個線程對象要快的多。

2、方便管理 可以編寫線程池管理代碼對池中的線程同一進行管理,比如說啓動時有該程序創建100個線程,每當有請求的時候,就分配一個線程去工作,如果剛好併發有101個請求,那多出的這一個請求可以排隊等候,避免因無休止的創建線程導致系統崩潰。

 

說說幾種常見的線程池及使用場景

1、newSingleThreadExecutor

創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

2、newFixedThreadPool

創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。

3、newCachedThreadPool

創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。

4、newScheduledThreadPool

創建一個定長線程池,支持定時及週期性任務執行。

 

線程池中的幾種重要的參數

corePoolSize就是線程池中的核心線程數量,這幾個核心線程,只是在沒有用的時候,也不會被回收

maximumPoolSize就是線程池中可以容納的最大線程的數量

keepAliveTime,就是線程池中除了核心線程之外的其他的最長可以保留的時間,因爲在線程池中,除了核心線程即使在無任務的情況下也不能被清                                除,其餘的都是有存活時間的,意思就是非核心線程可以保留的最長的空閒時間,

util,就是計算這個時間的一個單位。

workQueue,就是等待隊列,任務可以儲存在任務隊列中等待被執行,執行的是FIFIO原則(先進先出)。

threadFactory,就是創建線程的線程工廠。

handler,是一種拒絕策略,我們可以在任務滿了之後,拒絕執行某些任務。

 

說說線程池的拒絕策略

    當請求任務不斷的過來,而系統此時又處理不過來的時候,我們需要採取的策略是拒絕服務。RejectedExecutionHandler接口提供了拒絕任務處理的自定義方法的機會。在ThreadPoolExecutor中已經包含四種處理策略。

AbortPolicy策略:該策略會直接拋出異常,阻止系統正常工作。

CallerRunsPolicy 策略:只要線程池未關閉,該策略直接在調用者線程中,運行當前的被丟棄的任務。

DiscardOleddestPolicy策略: 該策略將丟棄最老的一個請求,也就是即將被執行的任務,並嘗試再次提交當前任務。

DiscardPolicy策略:該策略默默的丟棄無法處理的任務,不予任何處理。

    除了JDK默認提供的四種拒絕策略,我們可以根據自己的業務需求去自定義拒絕策略,自定義的方式很簡單,直接實現RejectedExecutionHandler接口即可。

 

execute和submit的區別?

    在前面的講解中,我們執行任務是用的execute方法,除了execute方法,還有一個submit方法也可以執行我們提交的任務。

這兩個方法有什麼區別呢?分別適用於在什麼場景下呢?我們來做一個簡單的分析。

execute適用於不需要關注返回值的場景,只需要將線程丟到線程池中去執行就可以了。

submit方法適用於需要關注返回值的場景

 

五種線程池的使用場景

newSingleThreadExecutor:一個單線程的線程池,可以用於需要保證順序執行的場景,並且只有一個線程在執行。

newFixedThreadPool:一個固定大小的線程池,可以用於已知併發壓力的情況下,對線程數做限制。

newCachedThreadPool:一個可以無限擴大的線程池,比較適合處理執行時間比較小的任務。

newScheduledThreadPool:可以延時啓動,定時啓動的線程池,適用於需要多個後臺線程執行週期任務的場景。

newWorkStealingPool:一個擁有多個任務隊列的線程池,可以減少連接數,創建當前可用cpu數量的線程來並行執行。

 

線程池的關閉

關閉線程池可以調用shutdownNow和shutdown兩個方法來實現

shutdownNow:對正在執行的任務全部發出interrupt(),停止執行,對還未開始執行的任務全部取消,並且返回還沒開始的任務列表。

shutdown:當我們調用shutdown後,線程池將不再接受新的任務,但也不會去強制終止已經提交或者正在執行中的任務。

 

初始化線程池時線程數的選擇

如果任務是IO密集型,一般線程數需要設置2倍CPU數以上,以此來儘量利用CPU資源。

如果任務是CPU密集型,一般線程數量只需要設置CPU數加1即可,更多的線程數也只能增加上下文切換,不能增加CPU利用率。

上述只是一個基本思想,如果真的需要精確的控制,還是需要上線以後觀察線程池中線程數量跟隊列的情況來定。

 

線程池都有哪幾種工作隊列

1、ArrayBlockingQueue

是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。

2、LinkedBlockingQueue

一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列

3、SynchronousQueue

一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。

4、PriorityBlockingQueue

一個具有優先級的無限阻塞隊列。
————————————————
版權聲明:本文爲CSDN博主「Linias」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_29373285/article/details/85238728

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章