線程池拒絕策略 開發中常用什么策略_面試官:說說你知道多少種線程池拒絕策略...

往期文章

為什么阿里Java規約要求謹慎使用SimpleDateFormathttps://www.toutiao.com/i6696127929048367629/

為什么我強烈推薦你用枚舉來實現單例模式https://www.toutiao.com/i6696861933687013901/

為什么不要在MySQL中使用UTF-8編碼方式https://www.toutiao.com/i6697966437727732235/

前言

線程池,相信很多人都有用過,沒用過相信的也有學習過。但是,線程池的拒絕策略,相信知道的人會少許多。

四種線程池拒絕策略

當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize時,如果還有任務到來就會采取任務拒絕策略,通常有以下四種策略:

ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新提交被拒絕的任務ThreadPoolExecutor.CallerRunsPolicy:由調用線程(提交任務的線程)處理該任務

線程池默認的拒絕策略

既然有四種拒絕策略可以選擇,那么線程池的默認拒絕策略是什么呢?查看java.util.concurrent.ThreadPoolExecutor類的源碼,我們可以看到:

/** * The default rejected execution handler */private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

線程池的默認拒絕策略為AbortPolicy,即丟棄任務并拋出RejectedExecutionException異常。我們可以通過代碼來驗證這一點,現有如下代碼:

public class ThreadPoolTest {? public static void main(String[] args) {? BlockingQueue queue = new ArrayBlockingQueue<>(100); ThreadFactory factory = r -> new Thread(r, "test-thread-pool"); ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.SECONDS, queue, factory); while (true) { executor.submit(() -> { try { System.out.println(queue.size()); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } }); } }?}

這里是一個默認的線程池,沒有設置拒絕策略,設置了最大線程隊列是100。運行代碼:

894114fe1c34e2b21197ce638ed1e713.png

結果是符合預期的,這也證明了線程池的默認拒絕策略是ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。

設置線程池拒絕策略

如果我們想要根據實際業務場景需要,設置其他的線程池拒絕策略,可以通過ThreadPoolExecutor重載的構造方法進行設置:

bde16900379230287056d47af9cd01c9.png

現在的開發中,相信大家都有使用spring,其實我們也可以通過spring提供的org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor構建線程池。如下:

0c8a186db3b5e5a0a82331130dc33e97.png
@Configurationpublic class TaskExecutorConfig implements AsyncConfigurer { /** * Set the ThreadPoolExecutor's core pool size. */ private static final int CORE_POOL_SIZE = 5; /** * Set the ThreadPoolExecutor's maximum pool size. */ private static final int MAX_POOL_SIZE = 5; /** * Set the capacity for the ThreadPoolExecutor's BlockingQueue. */ private static final int QUEUE_CAPACITY = 1000;? /** * 通過重寫getAsyncExecutor方法,制定默認的任務執行由該方法產生 * 

* 配置類實現AsyncConfigurer接口并重寫getAsyncExcutor方法,并返回一個ThreadPoolTaskExevutor * 這樣我們就獲得了一個基于線程池的TaskExecutor */ @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(CORE_POOL_SIZE); taskExecutor.setMaxPoolSize(MAX_POOL_SIZE); taskExecutor.setQueueCapacity(QUEUE_CAPACITY); taskExecutor.initialize(); taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); return taskExecutor; }}

通過ThreadPoolTaskExecutor的setRejectedExecutionHandler設置拒絕策略即可。

拒絕策略場景分析

AbortPolicy

ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。

A handler for rejected tasks that throws a {@code RejectedExecutionException}.

這是線程池默認的拒絕策略,在任務不能再提交的時候,拋出異常,及時反饋程序運行狀態。如果是比較關鍵的業務,推薦使用此拒絕策略,這樣子在系統不能承載更大的并發量的時候,能夠及時的通過異常發現。

DiscardPolicy

ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。如果線程隊列已滿,則后續提交的任務都會被丟棄,且是靜默丟棄。

A handler for rejected tasks that silently discards therejected task.

使用此策略,可能會使我們無法發現系統的異常狀態。建議是一些無關緊要的業務采用此策略。例如,本人的博客網站統計閱讀量就是采用的這種拒絕策略。

DiscardOldestPolicy

ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新提交被拒絕的任務。

A handler for rejected tasks that discards the oldest unhandled request and then retries {@code execute}, unless the executor is shut down, in which case the task is discarded.

此拒絕策略,是一種喜新厭舊的拒絕策略。是否要采用此種拒絕策略,還得根據實際業務是否允許丟棄老任務來認真衡量。

CallerRunsPolicy

ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

A handler for rejected tasks that runs the rejected task directly in the calling thread of the {@code execute} method, unless the executor has been shut down, in which case the task is discarded.

如果任務被拒絕了,則由調用線程(提交任務的線程)直接執行此任務,我們可以通過代碼來驗證這一點:

把之前的代碼修改如下:

public static void main(String[] args) {? BlockingQueue queue = new ArrayBlockingQueue<>(10); ThreadFactory factory = r -> new Thread(r, "test-thread-pool"); ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.SECONDS, queue, factory, new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < 1000; i++) { executor.submit(() -> { try { System.out.println(Thread.currentThread().getName() + ":執行任務"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }); }}
382c28f64487bea197621cc871ee4861.png

把隊列最大值改為10,打印輸出線程的名稱。執行結果如下:

e7100f7247a05821d56cbe3cb7addc7a.png

通過結果可以看到,主線程main也執行了任務,這正說明了此拒絕策略由調用線程(提交任務的線程)直接執行被丟棄的任務的。

總結

本文介紹和演示了四種線程池拒絕策略,具體使用哪種策略,還得根據實際業務場景才能做出抉擇。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532091.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532091.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532091.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

css html 雙面打印_從 Linux 命令行進行打印 | Linux 中國

導讀&#xff1a;在 Linux 命令行進行打印的內容比單單一個 lp 命令多得多&#xff0c;讓我們來看一些可用選項。       本文字數&#xff1a;4305&#xff0c;閱讀時長大約&#xff1a;5分鐘https://linux.cn/article-13012-1.html作者&#xff1a;Sandra Henry-stocker譯…

python保存快捷鍵是什么_python常用快捷鍵

最重要的快捷鍵1. ctrlshiftA:萬能命令行2. shift兩次:查看資源文件新建工程第一步操作1. module設置把空包分層去掉,compact empty middle package2. 設置當前的工程是utf-8,設置的Editor-->File Encodings-->全部改成utf-8,注釋1. ctrl/:單行注釋光標操作1. ctrlaltent…

服務器內存超限問題_服務器內存爆滿最佳處置方案

內存爆滿截圖&#xff1a;分析&#xff1a;內存持續飆升&#xff0c;應該是有大量內存一直沒有釋放&#xff0c;考慮僵尸對象&#xff0c;僵尸進程&#xff0c;最簡單的就是重啟服務器&#xff0c;但是就無法找到罪魁禍首了。驗證&#xff1a;top命令查看活躍進程的資源使用情況…

js map對象遍歷_何時使用 Map 來代替變通的 JS 對象

JS 普通對象 {key: value} 用于存放結構化數據。但有一件事我覺得很煩:對象鍵必須是字符串(或很少使用的 symbol)。如果將數字用作鍵會怎樣&#xff1f;在這種情況下不會有錯誤&#xff1a;const names { 1: One, 2: Two,};Object.keys(names); // > [1, 2]JS 會隱式地將…

mysql怎么顯示結果窗口_mysql8中窗口函數

在以前的MySQL版本中是沒有窗口函數的&#xff0c;直到MySQL8.0才引入了窗口函數。窗口函數是對查詢中的每一條記錄執行一個計算&#xff0c;并且這個計算結果是用與該條記錄相關的多條記錄得到的。1.窗口函數與聚合函數窗口函數與聚合函數很像&#xff0c;他們都是在一組記錄而…

python控制臺輸入字符串作為參數_Python-如何將字符串傳遞到subprocess.Popen(使用stdin參數)?...

小編典典Popen.communicate() 說明文件&#xff1a;請注意&#xff0c;如果要將數據發送到進程的stdin&#xff0c;則需要使用stdin PIPE創建Popen對象。同樣&#xff0c;要在結果元組中獲得除None以外的任何內容&#xff0c;你還需要提供stdout PIPE和/或stderr PIPE。替換…

log4jdbc mysql_[簡單]log4jdbc-log4j2配置簡記_MySQL

log4jdbc-log4j2&#xff0c;就不多說了&#xff0c;不了解的可以谷歌&#xff0c;附上log4jdbc-log4j2的官方鏈接&#xff1a;https://code.google.com/p/log4jdbc-log4j2/ &#xff0c;上面有非常詳細的介紹。簡單的貼下配置文件&#xff0c;其他的見附件&#xff1a;databas…

vb實時錯誤6 溢出_java內存溢出系列(6): Out of swap space?

本文是java內存溢出系列第6小篇。JVM啟動參數指定了最大內存限制。如 -Xmx 以及相關的其他啟動參數. 假若JVM使用的內存總量超過可用的物理內存, 操作系統就會用到虛擬內存。錯誤信息 java.lang.OutOfMemoryError: Out of swap space? 表明, 交換空間(swap space,虛擬內存) 不…

java備份還原mysql數據庫_Java備份還原Mysql數據庫

///實體類package com.ews.util;/*** 系統備份展示對象** */public class DataFile {private String fileName;//備份文件的名稱private String fileDate;//備份文件的日期private String filePath;//備份文件的地址private String fileSize;//備份文件的大小public String get…

學pyqt5之前需要學python嗎_快速學習pyqt5(1)--入門

學習于&#xff1a;PyQt5圖形界面編程 想要系統學習的同學建議可以去這個專欄好好學習&#xff0c;沒有任何語言基礎和計算機基礎的也建議直接去看那個專欄。我這里是有java基礎了&#xff0c;所以就不重復&#xff0c;針對快速學習使用。學習這個的目的是完成學校的SIT項目&am…

reboot mysql fail_mysql 5.7.18,在系統重啟后,為什么無法啟動?

度娘也不給力&#xff0c;只好自己研究了。先把結論寫出來吧。把pid文件換個位置&#xff0c;就好了。問題是&#xff0c; mysqld.servce的文件是從mysql的安裝目錄拷貝的&#xff0c;導致沒有懷疑pid文件位置的問題。一開始還懷疑是不是自己在一些文件里拼寫有誤。后來&#x…

mysql 查看鎖_別吵吵,分布式鎖也是鎖

Tomcat是這個系統的核心組成部分&#xff0c; 每當有用戶請求過來&#xff0c;Tomcat就會從線程池里找個線程來處理&#xff0c;有的執行登錄&#xff0c;有的查看購物車&#xff0c;有的下訂單&#xff0c;看著屬下們盡心盡職地工作&#xff0c;完成人類的請求&#xff0c;Tom…

php解析js的 arraybuffer_JS的所謂的第七種數據類型Symbol

首先&#xff0c;為什么說叫所謂呢&#xff1f;因為在2007年之前Js給予我們typeof解析數據類型的一共有六種(一直有爭議&#xff0c;但是我們暫時就按typeof來算)functionNumberObjectbooleanStringundefined但當我們去 typeof Symbol () 的時候&#xff0c;會驚奇的發現&#…

JAVA MYSQL從數據庫中提取圖片_java web將圖片存到儲數據庫和從數據庫中讀取圖片...

(Notice&#xff1a;以下所有經驗也是我根據網上的經驗整理的&#xff0c;如有侵權可以聯系我刪除&#xff0c;Wx:IT_Ezra&#xff0c;QQ 654303408。 有問題討論也可聯系我&#xff0c;QQ同上。)一、分析一下基本流程從前臺頁面獲取圖片&#xff0c;后臺接收圖片文件轉化成數據…

Ubuntu系統如何安裝和卸載CUDA和CUDNN

背景 最近在學習PaddlePaddle在各個顯卡驅動版本的安裝和使用&#xff0c;所以同時也學習如何在Ubuntu安裝和卸載CUDA和CUDNN&#xff0c;在學習過程中&#xff0c;順便記錄學習過程。在供大家學習的同時&#xff0c;也在加強自己的記憶。本文章以卸載CUDA 8.0 和 CUDNN 7.05 …

session.merge 緩存不更新_如何保證緩存與數據庫雙寫時的數據一致性?

在做系統優化時&#xff0c;想到了將數據進行分級存儲的思路。因為在系統中會存在一些數據&#xff0c;有些數據的實時性要求不高&#xff0c;比如一些配置信息。基本上配置了很久才會變一次。而有一些數據實時性要求非常高&#xff0c;比如訂單和流水的數據。所以這里根據數據…

java替換圖片中文字_Java 添加、替換、刪除Word中的圖片

文檔中&#xff0c;可以通過圖文混排的方式來增加內容的可讀性&#xff0c;相比純文本文檔&#xff0c;在內容展現方式上也更具美觀性。在給文檔添加圖片時&#xff0c;可設置圖片的文本環繞方式、旋轉角度、圖片高度/寬度等&#xff1b;另外&#xff0c;也可對文檔中已有的圖片…

kafka如何保證不重復消費又不丟失數據_Kafka寫入的數據如何保證不丟失?

我們暫且不考慮寫磁盤的具體過程&#xff0c;先大致看看下面的圖&#xff0c;這代表了 Kafka 的核心架構原理。Kafka 分布式存儲架構那么現在問題來了&#xff0c;如果每天產生幾十 TB 的數據&#xff0c;難道都寫一臺機器的磁盤上嗎?這明顯是不靠譜的啊!所以說&#xff0c;這…

不允許輸入特殊字符的正則表達式_JavaScript正則表達式常用技巧

正則表達式是用于匹配字符串中字符組合的模式。在 JavaScript 中&#xff0c;正則表達式也是對象。這些模式被用于 RegExp 的 exec 和 test 方法, 以及 String 的 match、matchAll、replace、search 和 split 方法。正則表達式的掌握程度能粗略地看出程序員的技術底子&#xff…

latex 算法_GitHub項目awesome-latex-drawing新增內容(四):繪制貝葉斯網絡

近期&#xff0c;我們整理和開源了一個基于LaTeX的科技繪圖項目&#xff0c;并將其取名為awesome-latex-drawing&#xff08;GitHub網址為&#xff1a;https://github.com/xinychen/awesome-latex-drawing&#xff09;&#xff0c;案例包括貝葉斯網絡、圖模型、矩陣/張量示意圖…