線程池拒絕策略:優(yōu)雅處理過載請(qǐng)求
什么是線程池拒絕策略?
線程池拒絕策略是指當(dāng)線程池中的任務(wù)數(shù)量達(dá)到上限時(shí),新提交的任務(wù)如何處理的一種策略。Java 提供了幾種內(nèi)置的拒絕策略,開發(fā)者也可以自定義策略。
內(nèi)置的拒絕策略
Java 提供了以下幾種內(nèi)置的拒絕策略:
- AbortPolicy:默認(rèn)策略,直接拋出 RejectedExecutionException 異常,阻止系統(tǒng)正常運(yùn)行。
- CallerRunsPolicy:由調(diào)用線程處理該任務(wù),既不拋棄任務(wù),也不拋出異常。
- DiscardPolicy:直接丟棄任務(wù),不予處理。
- DiscardOldestPolicy:丟棄最舊的任務(wù),然后嘗試重新提交被拒絕的任務(wù)。
下面,我們通過代碼示例來詳細(xì)講述這些策略的實(shí)現(xiàn)和應(yīng)用。
代碼示例
創(chuàng)建一個(gè)簡單的線程池:
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 作為任務(wù)隊(duì)列,容量為 2
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
// 創(chuàng)建線程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
queue
);
// 提交任務(wù)
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();
}
});
}
// 關(guān)閉線程池
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();
}
}
來點(diǎn)通俗易懂的
為了更好地理解這些拒絕策略,我們可以將其類比于生活中的場景:
- AbortPolicy:就像餐廳已滿員,不再接待新客人,并告知客人“已經(jīng)客滿,請(qǐng)去別處”。
- CallerRunsPolicy:就像餐廳忙不過來時(shí),老板自己上陣服務(wù)客人,保證所有客人都能被服務(wù)到。
- DiscardPolicy:就像餐廳已滿員,直接不理會(huì)新來的客人,不告知任何信息。
- DiscardOldestPolicy:就像餐廳已滿員,把最早來但還沒點(diǎn)菜的客人請(qǐng)走,以便接待新來的客人。
自定義拒絕策略
除了內(nèi)置的拒絕策略,開發(fā)者還可以根據(jù)實(shí)際需求自定義拒絕策略。例如,記錄日志、發(fā)送通知等。
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");
// 這里可以添加更多處理邏輯,比如記錄日志、發(fā)送通知等
}
}
);
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();
}
}
結(jié)語
通過本文的介紹和代碼示例,相信大家對(duì) Java 線程池的拒絕策略有了更深入的理解。在實(shí)際開發(fā)中,選擇合適的拒絕策略能有效提升系統(tǒng)的穩(wěn)定性和用戶體驗(yàn)。