什么是线程池拒绝策略?
线程池拒绝策略是指当线程池中的任务数量达到上限时,新提交的任务如何处理的一种策略。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 线程池的拒绝策略有了更深入的理解。在实际开发中,选择合适的拒绝策略能有效提升系统的稳定性和用户体验。