「视频版」当线程池溢出之后,程序会奔溃吗?面试突击 007 期
哈嘍,大家好,我是老王,歡迎來到第 7 期的 Java 面試突擊。
本文的面試題是,當(dāng)線程池的任務(wù)溢出之后,程序會奔潰嗎?
這個問題問的是關(guān)于線程池的任務(wù)數(shù)超過線程池的承載能力之后,會出現(xiàn)什么情況?
那么,我們本文就手?jǐn)]模擬一個線程池溢出的情況,來看程序的執(zhí)行情況。
涉及知識點(diǎn)
核心線程數(shù)和最大線程數(shù)有什么區(qū)別?
如何模擬線程池溢出?
拒絕策略的執(zhí)行流程是什么?
什么是線程池的拒絕策略?
Java 自帶的拒絕策略有哪些?
如何自定義拒絕策略?
視頻面試答案
視頻內(nèi)容(因?yàn)橐曨l比較大,分成了兩個視頻來展示?):
圖文面試答案
當(dāng)線程池的任務(wù)溢出之后,程序并不會奔潰,這時(shí)候會觸發(fā)線程池的拒絕策略,Java 自帶的拒絕策略有四種:
AbortPolicy:終止策略,線程池終止執(zhí)行,并直接拋出異常,Java 默認(rèn)此拒絕策略;
CallerRunsPolicy:把任務(wù)交給當(dāng)前線程執(zhí)行(本來是線程池自己要執(zhí)行的,結(jié)果處理不過來就交給當(dāng)前的主線程去處理);
DiscardPolicy:忽略此任務(wù)(最新的任務(wù));
DiscardOldestPolicy:忽略最早的任務(wù)(最久的任務(wù))。
拒絕策略的執(zhí)行流程比較繞,這是因?yàn)榫€程池有三個重要的參數(shù):核心線程數(shù)(corePoolSize)、最大線程數(shù)(maximumPoolSize)、線程池的任務(wù)隊(duì)列(BlockingQueue),大部分搞不清楚核心線程數(shù)和最大線程數(shù)有什么區(qū)別?
核心線程數(shù)是指在正常情況下線程池內(nèi)的線程數(shù)量;而最大線程數(shù)指的是當(dāng)線程池的任務(wù)隊(duì)列存儲超過最大值之后,可以創(chuàng)建最多的線程數(shù)量。
當(dāng)任務(wù)比較少的時(shí)候,線程數(shù)量會根據(jù)設(shè)置的超時(shí)時(shí)間,回歸線程的數(shù)量為核心線程數(shù)量,這個時(shí)候最大線程數(shù)就暫時(shí)沒用了(沒有發(fā)揮的余地了)。
拒絕策略的執(zhí)行流程是:當(dāng)提交的任務(wù)數(shù)量大于核心線程數(shù)時(shí),任務(wù)會被放入到線程池的任務(wù)隊(duì)列中,當(dāng)任務(wù)超過了最大隊(duì)列值時(shí),判斷當(dāng)前線程數(shù)量是否大于最大線程數(shù),如果小于最大線程數(shù)則會新創(chuàng)建線程處理次任務(wù),相反的情況下就會執(zhí)行拒絕策略,如下圖所示:
模擬線程池溢出
public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 6; i++) {executor.execute(() -> {System.out.println(Thread.currentThread().getName());});}}程序的執(zhí)行結(jié)果如下:
pool-1-thread-2
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-4
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task org.example.App$$Lambda$1/1096979270@7cca494b rejected from java.util.concurrent.ThreadPoolExecutor@7ba4f24f[Running, pool size = 4, active threads = 4, queued tasks = 1, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at org.example.App.main(App.java:13)
從執(zhí)行結(jié)果可以看出,循環(huán)在執(zhí)行第 6?次就拋出異常了,這是因?yàn)樽畲缶€程數(shù)為 4,而隊(duì)列最大只能存儲 1 個任務(wù),所以在第 6?個任務(wù)過來的時(shí)候,線程池已經(jīng)超負(fù)荷運(yùn)行了,只能執(zhí)行拒絕策略了,而我們設(shè)置的拒絕策略是 AbortPolicy?所以會拋出異常。
自定義拒絕策略
除了 Java 自帶的四種拒絕策略外,我們還可以自定義拒絕策略,代碼如下:
public static void main(String[] args) throws InterruptedException {ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS,new LinkedBlockingQueue<>(1), new RejectedExecutionHandler() {@Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {// 添加業(yè)務(wù)處理代碼System.out.println("自定義拒絕策略");}});for (int i = 0; i < 7; i++) {executor.execute(() -> {System.out.println(Thread.currentThread().getName());});} }以上程序執(zhí)行結(jié)果如下:
自定義拒絕策略
自定義拒絕策略
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
可以看出自定義拒絕策略,只需要重寫 RejectedExecutionHandler 接口的 rejectedExecution 方法即可,可以在此方法中添加自己的業(yè)務(wù)處理代碼。
小結(jié)
本文講了線程池任務(wù)新增時(shí)的執(zhí)行流程,先判斷是否有空閑線程,如果的話直接執(zhí)行任務(wù),如果沒有的話再判斷任務(wù)隊(duì)列是否是否飽和,如果不飽和把任務(wù)存儲到隊(duì)列中,如果飽和需要判斷當(dāng)前線程數(shù)是否大于最大線程數(shù),如果小于則新增線程執(zhí)行此任務(wù),反之則執(zhí)行拒絕策略。Java 提供了四種拒絕策略,你可以通過重寫 RejectedExecutionHandler 接口來自定義拒絕策略。
更多執(zhí)行細(xì)節(jié)和更多知識點(diǎn)說明,詳見本文的視頻部分。
【END】
近期熱文
HashMap 為什么會導(dǎo)致 CPU 100%?面試突擊 006 期
面試突擊 005 | Redis 是如何實(shí)現(xiàn)高可用的?它的實(shí)現(xiàn)方式有哪些?
面試突擊 004 | 如何排查 Redis 中的慢查詢?視頻實(shí)戰(zhàn)篇
面試突擊 003 | Redis 如何實(shí)現(xiàn)查詢附近的人?
面試突擊 002 | Redis 是如何處理已過期元素的?
面試突擊 001 | Redis 如何從海量數(shù)據(jù)中查詢出某一個 Key?
Java面試詳解(2020版):500+ 面試題和核心知識點(diǎn)詳解
關(guān)注下方二維碼,訂閱更多精彩內(nèi)容
朕已閱?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的「视频版」当线程池溢出之后,程序会奔溃吗?面试突击 007 期的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Boot (八)MyBat
- 下一篇: 超3000岗位!腾讯产业互联网新年大扩招