线程池的 RejectedExecutionHandler(拒绝策略)
轉載自??https://blog.csdn.net/jgteng/article/details/54411423
https://blog.csdn.net/luofenghan/article/details/78596950
JAVA為多線程場景提供了線程池,下面是一個線程池的構造方法:
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), handler);}其中這些參數的使用和說明在我的一篇文章中已經有了介紹,如果不太清楚的可以參考這篇文章:http://blog.csdn.net/jgteng/article/details/54409887
這里想對拒絕策略RejectedExecutionHandler做一下詳細的介紹。
在使用線程池并且使用有界隊列的時候,如果隊列滿了,任務添加到線程池的時候就會有問題,針對這些問題java線程池提供了以下幾種策略:
- AbortPolicy?(中止)?
- DiscardPolicy?(拋棄)?
- DiscardOldestPolicy? (拋棄最舊)?
- CallerRunsPolicy?(調用者運行)
自定義
◇AbortPolicy
該策略是線程池的默認策略。使用該策略時,如果線程池隊列滿了丟掉這個任務并且拋出RejectedExecutionException異常。
- 該策略是默認的飽和策略;
- 會拋出未檢查的RejectedExecutionException,調用者可以捕獲這個異常,然后根據需求編寫自己的處理代碼;
源碼如下:
?public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {//不做任何處理,直接拋出異常throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());}◇DiscardPolicy
這個策略和AbortPolicy的slient版本,如果線程池隊列滿了,會直接丟掉這個任務并且不會有任何異常。
- 當提交的任務無法保存到隊列中等待執行時,Discard策略會悄悄拋棄該任務。
源碼如下:
? ?public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {//就是一個空的方法}◇DiscardOldestPolicy
- 會拋棄下一個將被執行的任務,然后嘗試重新提交的新任務。
- 如果工作隊列是一個優先隊列,那么拋棄最舊的策略,會拋棄優先級最高的任務,因此最好不要將拋棄最舊的飽和策略和優先級隊列放在一起使用。
源碼如下:
◇CallerRunsPolicy
- 該策略既不會拋棄任務,也不會拋出異常,而是當線程池中的所有線程都被占用后,并且工作隊列被填滿后,下一個任務會在調用execute時在主線程中執行,從而降低新任務的流量。由于執行任務需要一定的時間,因此主線程至少在一定的時間內不能提交任何任務,從而使得工作者線程有時間來處理正在執行的任務。
- 另一方面,在這期間,主線程不會調用accept,那么到達的請求將被保存在TCP層的隊列中而不是在應用程序的隊列中。如果持續過載,那么TCP層將最終發現他的請求隊列被填滿,因此同樣會開始拋棄請求。
- 當服務器過載時,這種過載情況會逐漸向外蔓延開來——從線程池到工作隊列到應用程序再到TCP層,最終到達客戶端,導致服務器在高負載的情況下實現一種平緩的性能降低。
源碼如下:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
? ? ? ? ? ? if (!e.isShutdown()) {
? ? ? ? ? ? ? ? //直接執行run方法
? ? ? ? ? ? ? ? r.run();
? ? ? ? ? ? }
? ? ? ? }
自定義
如果以上策略都不符合業務場景,那么可以自己定義一個拒絕策略,只要實現RejectedExecutionHandler接口,并且實現rejectedExecution方法就可以了。具體的邏輯就在rejectedExecution方法里去定義就OK了。
例如:我定義了我的一個拒絕策略,叫做MyRejectPolicy,里面的邏輯就是打印處理被拒絕的任務內容
這幾種策略沒有好壞之分,只是適用不同場景,具體哪種合適根據具體場景和業務需要選擇,如果需要特殊處理就自己定義好了。
?
總結
以上是生活随笔為你收集整理的线程池的 RejectedExecutionHandler(拒绝策略)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中System.setPrope
- 下一篇: Spring Boot系列二 Sprin