執行緒池的RejectedExecutionHandler(拒絕策略)
阿新 • • 發佈:2019-01-29
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
- 自定義
◇DiscardPolicy 這個策略和AbortPolicy的slient版本,如果執行緒池佇列滿了,會直接丟掉這個任務並且不會有任何異常。 原始碼如下:public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { //不做任何處理,直接丟擲異常 throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//就是一個空的方法
}
◇DiscardOldestPolicy 這個策略從字面上也很好理解,丟棄最老的。也就是說如果佇列滿了,會將最早進入佇列的任務刪掉騰出空間,再嘗試加入佇列。 因為佇列是隊尾進,隊頭出,所以隊頭元素是最老的,因此每次都是移除對頭元素後再嘗試入隊。 原始碼如下:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { //移除隊頭元素 e.getQueue().poll(); //再嘗試入隊 e.execute(r); } }
CallerRunsPolicy 使用此策略,如果新增到執行緒池失敗,那麼主執行緒會自己去執行該任務,不會等待執行緒池中的執行緒去執行。就像是個急脾氣的人,我等不到別人來做這件事就乾脆自己幹。 原始碼如下:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//直接執行run方法
r.run();
}
}
自定義 如果以上策略都不符合業務場景,那麼可以自己定義一個拒絕策略,只要實現RejectedExecutionHandler介面,並且實現rejectedExecution方法就可以了。具體的邏輯就在rejectedExecution方法裡去定義就OK了。 例如:我定義了我的一個拒絕策略,叫做MyRejectPolicy,裡面的邏輯就是列印處理被拒絕的任務內容
public class MyRejectPolicy implements RejectedExecutionHandler{
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//Sender是我的Runnable類,裡面有message欄位
if (r instanceof Sender) {
Sender sender = (Sender) r;
//直接列印
System.out.println(sender.getMessage());
}
}
}
這幾種策略沒有好壞之分,只是適用不同場景,具體哪種合適根據具體場景和業務需要選擇,如果需要特殊處理就自己定義好了。