線程池拒絕策略四大“送命題”:答錯一個,offer直接涼涼!
線程池的拒絕策略是指,當線程池無法承載更多任務時執行的行為。也就是當線程池的核心線程數、最大線程、任務隊列都滿的情況下,又來了新的任務時,線程池執行的行為被稱之為線程池的拒絕策略。
線程池的執行流程如下:
1.內置拒絕策略
在 Java 中,線程池內置了以下四種拒絕策略(Rejected Execution Policy)。
(1)AbortPolicy(中止策略)
- 行為:默認拒絕策略,直接拋出 RejectedExecutionException 異常。
- 特點:強制調用方處理任務被拒絕的情況。
- 適用場景:對任務丟失不敏感的場景。如果對丟失敏感需結合異常捕獲機制處理(記錄信息并告警)。
示例代碼:
new ThreadPoolExecutor(..., new ThreadPoolExecutor.AbortPolicy());
(2)CallerRunsPolicy(調用者運行策略)
- 行為:將任務退回給提交任務的線程(即調用 execute() 的線程),由該線程直接執行任務。
- 特點:變相降低任務提交速度,避免線程池過載。
- 適用場景:希望任務最終被處理,且能承受一定延遲(如日志記錄)。
示例效果:
// 假設線程池已滿,主線程提交任務時會直接執行該任務
executor.execute(task); // 主線程執行 task
(3)DiscardPolicy(丟棄策略)
- 行為:靜默丟棄被拒絕的任務,不拋出異常,也不執行任務。
- 特點:無感知丟棄,可能導致數據丟失。
- 適用場景:允許任務丟失的非關鍵場景(如實時監控數據采樣)。
示例代碼:
new ThreadPoolExecutor(..., new ThreadPoolExecutor.DiscardPolicy());
(4)DiscardOldestPolicy(丟棄最舊任務策略)
- 行為:丟棄工作隊列中等待時間最長的任務(即隊列頭部的任務),然后重新嘗試提交當前任務。
- 特點:優先處理新任務,但可能丟失重要舊任務。
- 適用場景:適合處理時效性較強的任務(如消息推送,新任務優先級更高)。
示例代碼:
new ThreadPoolExecutor(..., new ThreadPoolExecutor.DiscardOldestPolicy());
2.自定義拒絕策略
除了以上四種內置拒絕策略之外,程序中還可以通過實現 RejectedExecutionHandler 接口實現自定義策略:
public class CustomRejectionPolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
// 自定義邏輯(如記錄日志、持久化任務、重試等)
System.out.println("Task rejected: " + task);
// 保存任務信息
// 通知相關負責人
}
}
// 使用自定義策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, new CustomRejectionPolicy()
);
小結
策略 | 優點 | 缺點 | 適用場景 |
AbortPolicy | 默認拒絕策略,報錯提示 | 需處理異常,增加代碼復雜度 | 任務丟失不敏感的場景 |
CallerRunsPolicy | 任務一定執行 | 可能阻塞主線程,影響響應速度 | 非實時任務,允許延遲處理(如日志) |
DiscardPolicy | 簡單高效,無額外開銷 | 數據丟失風險高 | 可容忍數據丟失的場景(如監控采樣) |
DiscardOldestPolicy | 優先處理新任務 | 可能丟失重要舊任務 | 時效性強的任務(如實時消息推送) |
CustomRejectionPolicy | 靈活 | 實現復雜 | 通常用于生產環境,先保存任務信息,再報警提示負責人 |