jdk中關於線程池的拒絕策略的接口的實現,暫時就四個,如下:
AbortPolicy -- 當任務添加到線程池中被拒絕時,它將拋出 RejectedExecutionException 異常。
CallerRunsPolicy -- 當任務添加到線程池中被拒絕時,會在線程池當前正在運行的Thread線程池中處理被拒絕的任務。
DiscardOldestPolicy -- 當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然後將被拒絕的任務添加到等待隊列中。
DiscardPolicy -- 當任務添加到線程池中被拒絕時,線程池將丟棄被拒絕的任務。
真的是4個實現,圖裏面剩下的幾個是其它jar裏面的實現,可以不管。
只有第一個會拋異常,這個還是默認的拒絕策略,其它3個都是默默的消化掉問題。
當任務添加到線程池中之所以被拒絕,可能是由於:第一,線程池異常關閉。第二,任務數量超過線程池的最大限制。
測試,使用的runnable代碼
package com.lxk.thread.threadpool.executors.reject;
/**
* @author LiXuekai on 2020/3/27
*/
public class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
try {
String name = "當前線程名稱:" + Thread.currentThread().getName();
System.out.println(name + ", " + this.name + " is running.");
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面用代碼記錄一下幾個策略的使用場景。
1,AbortPolicy
package com.lxk.thread.threadpool.executors.reject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* AbortPolicy 當任務添加到線程池中被拒絕時,它將拋出 RejectedExecutionException 異常。
* <p>
* 結果說明:
* 將"線程池的拒絕策略"由DiscardPolicy修改爲AbortPolicy之後,當有任務添加到線程池被拒絕時,會拋出RejectedExecutionException。
*
* @author LiXuekai on 2020/3/27
*/
public class TestAbortPolicy {
private static final int THREADS_SIZE = 1;
private static final int TASK_MAX = 10;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("Test-Rejected-Policy-Pool-%d").build();
// 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1(THREADS_SIZE),"線程池"的阻塞隊列容量爲1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
// 新建10個任務,並將它們添加到線程池中。
for (int i = 0; i < TASK_MAX; i++) {
Runnable myRunnable = new MyRunnable("task [ " + i + " ]");
try {
pool.execute(myRunnable);
} catch (RejectedExecutionException e) {
System.out.println(e.toString());
}
}
// 關閉線程池
pool.shutdown();
}
}
運行結果:
只有0,1兩個任務運行OK,其它的8個任務,在往線程池丟的時候,被線程池拒絕了,而且還拋了異常,被catch住了,catch了8次。
2,CallerRunsPolicy
package com.lxk.thread.threadpool.executors.reject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* CallerRunsPolicy 當任務添加到線程池中被拒絕時,會在線程池當前正在運行的Thread線程池中處理被拒絕的任務
* 翻譯一下:就是不進入線程池執行,在這種方式(CallerRunsPolicy)中,任務將有調用者線程去執行
*
* @author LiXuekai on 2020/3/27
*/
public class TestCallerRunsPolicy {
private static final int THREADS_SIZE = 1;
private static final int TASK_MAX = 10;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("Test-Rejected-Policy-Pool-%d").build();
// 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1(THREADS_SIZE),"線程池"的阻塞隊列容量爲1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY), namedThreadFactory);
// 設置線程池的拒絕策略爲"CallerRunsPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 新建10個任務,並將它們添加到線程池中。
for (int i = 0; i < TASK_MAX; i++) {
Runnable myRunnable = new MyRunnable("task [ " + i + " ]");
try {
pool.execute(myRunnable);
} catch (Exception e) {
System.out.println(e.toString());
}
}
// 關閉線程池
pool.shutdown();
}
}
運行結果圖:
在任務往線程池丟的時候,發現線程池已經裝不下了,那麼這個時候,就讓往線程池丟任務丟這個線程來執行這個任務,在此例子就是main線程了,從結果圖可見線程池裏面的一個線程和main一起幹活,把10個任務給搞完了。
3,DiscardOldestPolicy
package com.lxk.thread.threadpool.executors.reject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然後將被拒絕的任務添加到等待隊列中。
* <p>
* 結果說明:
* 將"線程池的拒絕策略"由DiscardPolicy修改爲DiscardOldestPolicy之後,當有任務添加到線程池被拒絕時,
* 線程池會丟棄阻塞隊列中末尾的任務,然後將被拒絕的任務添加到末尾。
*
* @author LiXuekai on 2020/3/27
*/
public class TestDiscardOldestPolicy {
private static final int THREADS_SIZE = 1;
private static final int TASK_MAX = 10;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("Test-Rejected-Policy-Pool-%d").build();
// 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1(THREADS_SIZE),"線程池"的阻塞隊列容量爲1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY), namedThreadFactory);
// 設置線程池的拒絕策略爲"DiscardOldestPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
// 新建10個任務,並將它們添加到線程池中。
for (int i = 0; i < TASK_MAX; i++) {
Runnable myRunnable = new MyRunnable("task [ " + i + " ]");
try {
pool.execute(myRunnable);
} catch (Exception e) {
System.out.println(e.toString());
}
}
// 關閉線程池
pool.shutdown();
}
}
運行結果:
可見0任務到池子之後,運行,剩下1-9在來池子的時候,沒位置了,都的排隊,但位置就1個,那每次新來的都會不客氣但把舊時代的給擠掉。也就是這個策略的名字的由來。
4,DiscardPolicy
package com.lxk.thread.threadpool.executors.reject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* DiscardOldestPolicy -- 當任務添加到線程池中被拒絕時,線程池會放棄等待隊列中最舊的未處理任務,然後將被拒絕的任務添加到等待隊列中。
* 結果說明:線程池pool的"最大池大小"和"核心池大小"都爲1(THREADS_SIZE),這意味着"線程池能同時運行的任務數量最大隻能是1"。
* 線程池pool的阻塞隊列是ArrayBlockingQueue,ArrayBlockingQueue是一個有界的阻塞隊列,ArrayBlockingQueue的容量爲1。這也意味着線程池的阻塞隊列只能有一個線程池阻塞等待。
* 根據""中分析的execute()代碼可知:線程池中共運行了2個任務。第1個任務直接放到Worker中,通過線程去執行;第2個任務放到阻塞隊列中等待。其他的任務都被丟棄了!
*
* @author LiXuekai on 2020/3/27
*/
public class TestDiscardPolicy {
private static final int THREADS_SIZE = 1;
private static final int TASK_MAX = 10;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("Test-Rejected-Policy-Pool-%d").build();
// 創建線程池。線程池的"最大池大小"和"核心池大小"都爲1(THREADS_SIZE),"線程池"的阻塞隊列容量爲1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY), namedThreadFactory);
// 設置線程池的拒絕策略爲"丟棄"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
// 新建10個任務,並將它們添加到線程池中。
for (int i = 0; i < TASK_MAX; i++) {
Runnable myRunnable = new MyRunnable("task [ " + i + " ]");
try {
pool.execute(myRunnable);
} catch (Exception e) {
System.out.println(e.toString());
}
}
// 關閉線程池
pool.shutdown();
}
}
運行結果:
任務0來了池子,先搶佔了線程,可以執行,之後來的都的在隊列裏排隊,但隊列就一個位置,先來的佔着位置,後面的來只能看着,被無情的拋棄,所以,輸出結果就0,1兩個任務執行,其它的都消失了。
最後:
1,幾個代碼都是創建了一個 "最大池大小"和"核心池大小"都爲1 的線程池,意味着"線程池能同時運行的任務數量最大隻能是1"
2,創建線程池的時候,應該使用 ThreadPoolExecutor 這個構造函數,可以牢記複習線程池創建原理,另外還的使用帶factory參數的構造函數,可以設置池子中的線程的名稱,出問題的時候,也好排查。