jdk1.5版本新增了
JUC
併發包,其中一個包含執行緒池。
四種拒絕策略:
拒絕策略型別 | 說明 | |
---|---|---|
1 | ThreadPoolExecutor.AbortPolicy | 預設拒絕策略,拒絕任務並丟擲任務 |
2 | ThreadPoolExecutor.CallerRunsPolicy | 使用呼叫執行緒直接執行任務 |
3 | ThreadPoolExecutor.DiscardPolicy | 直接拒絕任務,不丟擲錯誤 |
4 | ThreadPoolExecutor.DiscardOldestPolicy | 觸發拒絕策略,只要還有任務新增,一直會丟棄阻塞佇列的最老的任務,並將新的任務加入 |
預先配置
配置執行緒池。
- 核心執行緒和最大執行緒都儘量設定的小一點,分別設定成 1 和 2
- 阻塞佇列設定固定長度的有界佇列,長度為 1
- 執行緒工廠設定預設執行緒工廠
// 核心執行緒數
int corePoolSize = 1;
// 最大執行緒數
int maximumPoolSize = 2;
// 執行緒存活時間
long keepAliveTime = 10;
// 執行緒存活時間單位
TimeUnit unit = TimeUnit.SECONDS;
// 有界佇列 遵循 FIFO 原則
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
// 執行緒工廠
ThreadFactory threadFactory = Executors.defaultThreadFactory();
建立執行緒任務
建立執行緒任務,一個執行緒任務執行一秒:
class TaskThread implements Runnable{
private int i;
public TaskThread(int i) {
this.i = i;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("執行任務:" + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
拒絕策略一:AbortPolicy
預設拒絕策略,拒絕任務並丟擲任務
// 拒絕策略 預設拒絕策略,拒絕任務並丟擲異常:
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler);
for (int i = 1; i <= 5; i++) {
try {
threadPool.execute(new TaskThread(i));
} catch (Exception e) {
System.out.println("【任務" + i + "】報錯:" + e.getMessage());
}
}
輸出
【任務】4報錯:Task com.test.controller.ThreadPoolController$TaskThread@5c0369c4 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
【任務】5報錯:Task com.test.controller.ThreadPoolController$TaskThread@31b7dea0 rejected from java.util.concurrent.ThreadPoolExecutor@50675690[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
執行任務:1
執行任務:3
執行任務:2
最大執行緒數 + 阻塞佇列 = 3,執行到4,5的時候就丟擲錯誤。這裡需要用 try catch
捕獲異常。任務1、2、3正常執行。
如果提交的任務都要執行,可以將丟擲的錯誤任務存入在redis中,然後定時從
redis
中獲取任務,再提交執行。
拒絕策略二:CallerRunsPolicy
呼叫執行緒執行多餘的任務。
更換拒絕策略,將上面的 AbortPolicy
換成 CallerRunsPolicy
。
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
執行任務,輸出:
執行任務:1
執行任務:4
執行任務:3
執行任務:2
執行任務:5
最大執行緒數 + 阻塞佇列 = 3,多餘的任務還是繼續被執行。
拒絕策略三:DiscardPolicy
拒絕任務,不會丟擲錯誤。
更換策略,將CallerRunsPolicy
換成DiscardPolicy
:
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
執行任務,輸出:
執行任務:1
執行任務:3
執行任務:2
多餘的執行緒任務提交被拒絕,而只執行最大執行緒數 + 阻塞佇列 數量的任務,並且不會丟擲錯誤。
拒絕策略四:DiscardOldestPolicy
只要還有任務新增,一直會丟棄阻塞佇列的最老的任務,並將新的任務加入到阻塞佇列中。
更換策略,將DiscardPolicy
換成DiscardOldestPolicy
:
RejectedExecutionHandler handler3 = new ThreadPoolExecutor.DiscardOldestPolicy();
執行任務,輸出:
執行任務:3
執行任務:1
執行任務:5
任務的執行順序是 核心執行緒數 —> 阻塞佇列 —> 最大執行緒數,其中任務1,任務3提交成功。
- 任務2因為在阻塞佇列中,
- 後面的任務4把任務2擠掉,
- 任務5又把任務4擠掉,所以最後執行的是任務5。
總結
本文介紹了執行緒四種拒絕策略,當工作任務大於最大執行緒 + 阻塞佇列會執行阻塞佇列。
- AbortPolicy 預設策略,拒絕任務,並丟擲異常
- CallerRunsPolicy 呼叫執行緒執行對於的任務
- DiscardPolicy 拒絕任務,不會丟擲異常
- DiscardOldestPolicy 有多餘的任務,把阻塞佇列最老的任務丟棄,放入新的任務,直到沒有新的任務。
如果覺得文章對你有幫助的話,請點個推薦吧!