后端 | Java | 線程池
筆記來源:Java入門基礎(chǔ)視頻教程,java零基礎(chǔ)自學(xué)就選黑馬程序員Java入門教程
一、線程池概述
概念:
線程池就是一個可以復(fù)用線程的技術(shù)。
不適用線程池的問題:
如果用戶每發(fā)起一個請求,后臺就創(chuàng)建一個新線程來處理,下次新任務(wù)來了又要創(chuàng)建新線程,而創(chuàng)建新線程的開銷是很大的,這樣會嚴重影響系統(tǒng)的性能。
工作原理:
線程池通過提供固定的核心線程(工作線程WorkThread)和任務(wù)隊列(WorkQueue)來工作,當核心線程都在忙時,新來的任務(wù)進入任務(wù)隊列,等待核心線程的處理。
二、線程池實現(xiàn)的API、參數(shù)說明
JDK5.0起提供了代表線程池的接口,ExecutorService。
ExcutorService常用方法:
void execute(Runnable command):執(zhí)行任務(wù)/命令,沒有返回值,一般用來執(zhí)行Runnable任務(wù)。
Future<T> submit(Callable<T> task):執(zhí)行任務(wù),返回未來任務(wù)對象獲取線程結(jié)果,一般拿來執(zhí)行Callable任務(wù)。
void submit():等任務(wù)執(zhí)行完畢后關(guān)閉線程池。
List<Runnable> shutdownNow():立刻關(guān)閉,停止正在執(zhí)行的任務(wù),并返回隊列中未執(zhí)行的任務(wù)。
如何得到一個線程池對象:
方式一:使用ExecutorService的實現(xiàn)類ThreadPoolExecutor自創(chuàng)建一個線程池對象。
ThreadPoolExecutor構(gòu)造器的參數(shù)說明:
指定線程池的線程數(shù)量(核心線程):corePoolSize,不能小于0。
指定線程池可支持的最大線程數(shù):maximumPoolSize,最大數(shù)量>=核心線程數(shù)量。
指定臨時線程的最大存活時間:keepAliveTime,不能小于0。
指定存活時間的單位(秒、分、時、天):unit,時間單位。
指定任務(wù)隊列:workQueue,不能為null。
指定用哪個線程工廠創(chuàng)建線程:threadFactory,不能為null。
指定線程忙,任務(wù)滿時,新任務(wù)來了怎么辦:handler,不能為null。
方式二:使用Executors(線程池的工具類)調(diào)用方法返回不同特點的線程池對象。
Executors的底層也是基于線程池的實現(xiàn)類ThreadPoolExecutor創(chuàng)建線程池對象的。
Executors得到線程池對象的常用方法:
public static ExecutorService newCachedThreadPool():線程數(shù)量隨著任務(wù)增加而增加,如果線程任務(wù)執(zhí)行完畢且空閑了一段時間則會被回收掉。
public static ExecutorService newFixedThreadPool(int nThreads):創(chuàng)建固定線程數(shù)量的線程池,如果某個線程因為執(zhí)行異常而結(jié)束,那么線程池會補充一個新線程替代它。
public static ExecutorService newStringThreadExecutor():創(chuàng)建只有一個線程的線程池對象,如果該線程出現(xiàn)異常而結(jié)束,那么線程池會補充一個新線程。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize):創(chuàng)建一個線程池,可以實現(xiàn)在給定的延遲后運行任務(wù),或者定期執(zhí)行任務(wù)。
Executors使用可能存在的陷阱:
大型并發(fā)系統(tǒng)環(huán)境中使用Executors如果不注意可能會出現(xiàn)系統(tǒng)風險。
可能會出現(xiàn)OOM錯誤(Java.lang.OutOfMemoryError)。
三、線程池處理Runnable任務(wù)
ThreadPoolExecutor創(chuàng)建線程池對象:
新任務(wù)拒絕策略:
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常,是默認的策略。
ThreadPoolExecutor.DiscardPolicy:丟棄任務(wù),但是不拋出異常,這是不推薦的做法。
ThreadPoolExecutor.DiscardOldestPolicy:拋棄隊列中等待最久的任務(wù),然后把當前任務(wù)加入隊列中。
ThreadPoolExecutor.CallerRunsPolicy:由主線程負責調(diào)用任務(wù)的run()方法從而繞過線程池直接執(zhí)行。
給一個任務(wù)給線程池處理:
四、線程池處理Callable任務(wù)
五、線程池常見面試題
臨時線程什么時候創(chuàng)建?
新任務(wù)提交時發(fā)現(xiàn)核心線程都在忙,任務(wù)隊列也滿了,并且還可以創(chuàng)建臨時線程,此時才會創(chuàng)建臨時線程。
什么時候會開始拒絕任務(wù)?
核心線程和臨時線程都在忙,任務(wù)隊列也滿了,新的任務(wù)過來的時候才會開始任務(wù)拒絕。