一、介紹
當Executor已經關閉(即執行了executorService.shutdown()方法後),並且Executor將有限邊界用於最大線程數量和工作隊列容量,且已經飽和時,在方法execute()中提交的新任務將被拒絕。
在以上述情況下,execute 方法將調用其 RejectedExecutionHandler 的 RejectedExecutionHandler.rejectedExecution(Java.lang.Runnable,
java.util.concurrent.ThreadPoolExecutor) 方法。
首先我們來看下RejectedExecutionHandler 的定義:
下面提供了四種預定義的處理程序策略:
(1) 默認的ThreadPoolExecutor.AbortPolicy 處理程序遭到拒絕將拋出運行時RejectedExecutionException;
(2) ThreadPoolExecutor.CallerRunsPolicy 線程調用運行該任務的 execute 本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度
(3) ThreadPoolExecutor.DiscardPolicy 不能執行的任務將被刪除;
(4) ThreadPoolExecutor.DiscardOldestPolicy 如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重複此過程)。
線程池默認會採用的是defaultHandler策略。首先看defaultHandler的定義:
再看看具體的AbortPolicy:
看一下其他拒絕策略的具體實現:
CallerRunsPolicy實現類:
DiscardPolicy實現類:
DiscardOldestPolicy實現類:
通過以上分析,我們都知道:這四個RejectedExecutionHandler的實現類都是ThreadPoolExecutor的靜態內部類。
二、測試案例
寫一個task:
- package com.npf.thread.test;
- public class Task implements Runnable {
- protected String name;
- public Task(String name) {
- super();
- this.name = name;
- }
- @Override
- public void run() {
- try {
- System.out.println(this.name + " is running.");
- Thread.sleep(500);
- } catch (Exception e) {
- }
- }
- }
1. AbortPolicy 示例
- package com.npf.thread.test;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.RejectedExecutionException;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- public class AbortPolicyDemo {
- public static void main(String[] args) {
- // 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1,"線程池"的阻塞隊列容量爲1。
- ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0,
- TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
- // 設置線程池的拒絕策略爲AbortPolicy
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
- try {
- // 新建10個任務,並將它們添加到線程池中
- for (int i = 0; i < 10; i++) {
- Runnable myTask = new Task("task-"+i);
- pool.execute(myTask);
- }
- } catch (RejectedExecutionException e) {
- e.printStackTrace();
- // 關閉線程池
- pool.shutdown();
- }
- }
- }
2. CallerRunsPolicy 示例
- package com.npf.thread.test;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- public class CallerRunsPolicyDemo {
- public static void main(String[] args) {
- // 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1,"線程池"的阻塞隊列容量爲1。
- ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0,
- TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
- // 設置線程池的拒絕策略爲CallerRunsPolicy
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
- // 新建10個任務,並將它們添加到線程池中
- for (int i = 0; i < 10; i++) {
- Runnable myTask = new Task("task-"+i);
- pool.execute(myTask);
- }
- // 關閉線程池
- pool.shutdown();
- }
- }
某一次運行結果,當有新任務添加到線程池被拒絕時,線程池會將被拒絕的任務添加到"線程池正在運行的線程"中去運行:
3. DiscardPolicy 示例
- package com.npf.thread.test;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- public class DiscardPolicyDemo {
- public static void main(String[] args) {
- // 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1,"線程池"的阻塞隊列容量爲1。
- ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0,
- TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
- // 設置線程池的拒絕策略爲DiscardPolicy
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
- // 新建10個任務,並將它們添加到線程池中
- for (int i = 0; i < 10; i++) {
- Runnable myTask = new Task("task-"+i);
- pool.execute(myTask);
- }
- // 關閉線程池
- pool.shutdown();
- }
- }
某一次運行結果,線程池pool的"最大池大小"和"核心池大小"都爲1,這意味着"線程池能同時運行的任務數量最大隻能是1"。線程池pool的阻塞隊列是ArrayBlockingQueue,ArrayBlockingQueue是一個有界的阻塞隊列,ArrayBlockingQueue的容量爲1。這也意味着線程池的阻塞隊列只能有一個線程池阻塞等待。由此可知,線程池中共運行了2個任務。第1個任務直接放到Worker中,通過線程去執行;第2個任務放到阻塞隊列中等待。其他的任務都被丟棄了。
4.
DiscardOldestPolicy 示例
- package com.npf.thread.test;
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.ThreadPoolExecutor;
- import java.util.concurrent.TimeUnit;
- public class DiscardOldestPolicyDemo {
- public static void main(String[] args) {
- // 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1,"線程池"的阻塞隊列容量爲1。
- ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0,
- TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1));
- // 設置線程池的拒絕策略爲DiscardOldestPolicy
- pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
- // 新建10個任務,並將它們添加到線程池中
- for (int i = 0; i < 10; i++) {
- Runnable myTask = new Task("task-"+i);
- pool.execute(myTask);
- }
- // 關閉線程池
- pool.shutdown();
- }
- }
某一次運行結果,當有新任務添加到線程池被拒絕時,線程池會丟棄阻塞隊列中末尾的任務,然後將被拒絕的任務添加到末尾。