線程池拒絕策略:優雅處理過載請求
什么是線程池拒絕策略?
線程池拒絕策略是指當線程池中的任務數量達到上限時,新提交的任務如何處理的一種策略。Java 提供了幾種內置的拒絕策略,開發者也可以自定義策略。

內置的拒絕策略
Java 提供了以下幾種內置的拒絕策略:
- AbortPolicy:默認策略,直接拋出 RejectedExecutionException 異常,阻止系統正常運行。
- CallerRunsPolicy:由調用線程處理該任務,既不拋棄任務,也不拋出異常。
- DiscardPolicy:直接丟棄任務,不予處理。
- DiscardOldestPolicy:丟棄最舊的任務,然后嘗試重新提交被拒絕的任務。
下面,我們通過代碼示例來詳細講述這些策略的實現和應用。
代碼示例
創建一個簡單的線程池:
import java.util.concurrent.*;
public class ThreadPoolExample {
private static final int CORE_POOL_SIZE = 2;
private static final int MAX_POOL_SIZE = 4;
private static final long KEEP_ALIVE_TIME = 10L;
public static void main(String[] args) {
// 使用 ArrayBlockingQueue 作為任務隊列,容量為 2
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
// 創建線程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
queue
);
// 提交任務
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
executor.submit(() -> {
try {
System.out.println("Executing task " + taskNumber);
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 關閉線程池
executor.shutdown();
}
}使用 AbortPolicy:
import java.util.concurrent.*;
public class AbortPolicyExample {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10L, TimeUnit.SECONDS, queue,
new ThreadPoolExecutor.AbortPolicy() // 使用 AbortPolicy
);
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
try {
executor.submit(() -> {
try {
System.out.println("Executing task " + taskNumber);
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
} catch (RejectedExecutionException e) {
System.err.println("Task " + taskNumber + " was rejected");
}
}
executor.shutdown();
}
}使用 CallerRunsPolicy:
import java.util.concurrent.*;
public class CallerRunsPolicyExample {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10L, TimeUnit.SECONDS, queue,
new ThreadPoolExecutor.CallerRunsPolicy() // 使用 CallerRunsPolicy
);
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
executor.submit(() -> {
System.out.println("Executing task " + taskNumber);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}使用 DiscardPolicy:
import java.util.concurrent.*;
public class DiscardPolicyExample {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10L, TimeUnit.SECONDS, queue,
new ThreadPoolExecutor.DiscardPolicy() // 使用 DiscardPolicy
);
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
executor.submit(() -> {
System.out.println("Executing task " + taskNumber);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}使用 DiscardOldestPolicy:
import java.util.concurrent.*;
public class DiscardOldestPolicyExample {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10L, TimeUnit.SECONDS, queue,
new ThreadPoolExecutor.DiscardOldestPolicy() // 使用 DiscardOldestPolicy
);
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
executor.submit(() -> {
System.out.println("Executing task " + taskNumber);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}來點通俗易懂的
為了更好地理解這些拒絕策略,我們可以將其類比于生活中的場景:
- AbortPolicy:就像餐廳已滿員,不再接待新客人,并告知客人“已經客滿,請去別處”。
- CallerRunsPolicy:就像餐廳忙不過來時,老板自己上陣服務客人,保證所有客人都能被服務到。
- DiscardPolicy:就像餐廳已滿員,直接不理會新來的客人,不告知任何信息。
- DiscardOldestPolicy:就像餐廳已滿員,把最早來但還沒點菜的客人請走,以便接待新來的客人。
自定義拒絕策略
除了內置的拒絕策略,開發者還可以根據實際需求自定義拒絕策略。例如,記錄日志、發送通知等。
import java.util.concurrent.*;
public class CustomRejectionPolicyExample {
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 10L, TimeUnit.SECONDS, queue,
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println("Task " + r.toString() + " was rejected");
// 這里可以添加更多處理邏輯,比如記錄日志、發送通知等
}
}
);
for (int i = 0; i < 10; i++) {
final int taskNumber = i + 1;
executor.submit(() -> {
System.out.println("Executing task " + taskNumber);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}結語
通過本文的介紹和代碼示例,相信大家對 Java 線程池的拒絕策略有了更深入的理解。在實際開發中,選擇合適的拒絕策略能有效提升系統的穩定性和用戶體驗。

































