更新時間:2020-03-11 10:20:35 來源:動力節(jié)點 瀏覽6675次
Java通過Executors提供四種線程池
ThreadPoolExecutor的執(zhí)行流程
ThreadPoolExecutor的幾個參數(shù)
corePoolSize:核心池的大小,這個參數(shù)跟后面講述的線程池的實現(xiàn)原理有非常大的關系。在創(chuàng)建了線程池后,默認情況下,線程池中并沒有任何線程,而是等待有任務到來才創(chuàng)建線程去執(zhí)行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預創(chuàng)建線程的意思,即在沒有任務到來之前就創(chuàng)建corePoolSize個線程或者一個線程。默認情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當有任務來之后,就會創(chuàng)建一個線程去執(zhí)行任務,當線程池中的線程數(shù)目達到corePoolSize后,就會把到達的任務放到緩存隊列當中。
maximumPoolSize:線程池最大線程數(shù),這個參數(shù)也是一個非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個線程;如果當前阻塞隊列滿了,且繼續(xù)提交任務,則創(chuàng)建新的線程執(zhí)行任務,前提是當前線程數(shù)小于maximumPoolSize;當阻塞隊列是無界隊列,則maximumPoolSize不起作用,因為無法提交至核心線程池的線程會一直持續(xù)地放入workQueue(工作隊列)中。
keepAliveTime:表示線程沒有任務執(zhí)行時最多保持多久時間會終止。默認情況下,只有當線程池中的線程數(shù)大于corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數(shù)不大于corePoolSize,即當線程池中線程數(shù)大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止,直到線程池中的線程數(shù)不超過corePoolSize。但是如果調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時,keepAliveTime參數(shù)也會起作用,直到線程池中的線程數(shù)為0。
allowCoreThreadTimeout:默認情況下超過keepAliveTime的時候,核心線程不會退出,可通過將該參數(shù)設置為true,讓核心線程也退出。
unit:可以指定keepAliveTime的時間單位。
workQueue
ArrayBlockingQueue有界隊列,需要指定隊列大小。
LinkedBlockingQueue若指定大小則和ArrayBlockingQueue類似,若不指定大小則默認能存儲Integer.MAX_VALUE個任務,相當于無界隊列,此時maximumPoolSize值其實是無意義的。
SynchronousQueue同步阻塞隊列,當有任務添加進來后,必須有線程從隊列中取出,當前線程才會被釋放,newCachedThreadPool就使用這種隊列。
RejectedExecutionHandler:線程數(shù)和隊列都滿的情況下,線程池會執(zhí)行的拒絕策略,有四個(也可以使用自定義的策略)。
線程池的四種拒絕策略
Executors和ThreadPoolExecutor創(chuàng)建線程的區(qū)別
Executors
newFixedThreadPool和newSingleThreadExecutor:主要問題是堆積的請求處理隊列可能會耗費非常大的內存,甚至OOM。
newCachedThreadPool和newScheduledThreadPool:主要問題是線程數(shù)最大數(shù)是Integer.MAX_VALUE(2的31次方-1,int類型最大值),可能會創(chuàng)建數(shù)量非常多的線程,甚至OOM。
ThreadPoolExecutor
創(chuàng)建線程池方式只有一種,就是走它的構造函數(shù),參數(shù)自己指定。
為什么使用線程池
減少了創(chuàng)建和銷毀線程的次數(shù),每個工作線程都可以被重復利用,可執(zhí)行多個任務。
運用線程池能有效的控制線程最大并發(fā)數(shù),可以根據(jù)系統(tǒng)的承受能力,調整線程池中工作線線程的數(shù)目,防止因為消耗過多的內存,而把服務器累趴下(每個線程需要大約1MB內存,線程開的越多,消耗的內存也就越大,最后死機)。
對線程進行一些簡單的管理,比如:延時執(zhí)行、定時循環(huán)執(zhí)行的策略等,運用線程池都能進行很好的實現(xiàn)。
如何向線程池中提交任務
可以通過execute()或submit()兩個方法向線程池提交任務。
execute()方法沒有返回值,所以無法判斷任務知否被線程池執(zhí)行成功。
submit()方法返回一個future,那么我們可以通過這個future來判斷任務是否執(zhí)行成功,通過future的get方法來獲取返回值。
如何關閉線程池
可以通過shutdown()或shutdownNow()方法來關閉線程池。
shutdown的原理是只是將線程池的狀態(tài)設置成SHUTDOWN狀態(tài),然后中斷所有沒有正在執(zhí)行任務的線程。
shutdownNow的原理是遍歷線程池中的工作線程,然后逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止。shutdownNow會首先將線程池的狀態(tài)設置成STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務的線程,并返回等待執(zhí)行任務的列表。

以上就是動力節(jié)點Java培訓機構小編介紹的“程序員常見的Java線程池面試題”的內容,希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為你服務。