ThreadPoolExecutor
是 Java 并发库中一个强大的工具,它提供了几种不同的拒绝策略(RejectedExecutionHandler
),用于处理当线程池无法接受新任务时的情况。这通常发生在任务队列已满且线程池中的工作线程数已达到 maximumPoolSize
时。如果未指定拒绝策略,默认的策略是 AbortPolicy
。
内置的拒绝策略
-
AbortPolicy(默认):
- 行为:直接抛出
RejectedExecutionException
,通知调用者任务被拒绝。 - 用法:适用于不能丢弃任务且期望调用者处理被拒绝任务的场景。
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
- 行为:直接抛出
-
CallerRunsPolicy:
- 行为:由调用线程来执行该任务。这种策略可以减缓向线程池提交任务的速度。
- 用法:适用于能够容忍任务执行在调用线程中的场景,有助于降低新任务提交的速率。
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
-
DiscardPolicy:
- 行为:直接丢弃任务,不抛出异常。
- 用法:适用于可以容忍任务丢失的情境,比如日志记录或统计任务。
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
-
DiscardOldestPolicy:
- 行为:丢弃任务队列中最早的任务(即队头任务),然后重新尝试提交当前任务。
- 用法:适用于需要丢弃旧任务以确保新任务被执行的情境。
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
示例代码
下面是一个示例,展示了如何使用各个拒绝策略:
import java.util.concurrent.*;
public class RejectedExecutionHandlerExample {
public static void main(String[] args) {
// 核心参数配置
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
// 修改这个变量以测试不同的拒绝策略
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
// RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
// RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
// RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();
// 创建线程池
ExecutorService threadPool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
Executors.defaultThreadFactory(),
handler);
for (int i = 0; i < 10; i++) {
final int taskNumber = i;
try {
threadPool.submit(() -> {
try {
System.out.println("Task " + taskNumber + " is running by " + Thread.currentThread().getName());
Thread.sleep(2000); // 模拟任务执行时间
System.out.println("Task " + taskNumber + " is completed by " + Thread.currentThread().getName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
} catch (RejectedExecutionException e) {
System.out.println("Task " + taskNumber + " was rejected");
}
}
// 关闭线程池
threadPool.shutdown();
try {
if (!threadPool.awaitTermination(60, TimeUnit.SECONDS)) {
threadPool.shutdownNow();
}
} catch (InterruptedException ex) {
threadPool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
配置策略
您可以通过构造 ThreadPoolExecutor
时传入合适的 RejectedExecutionHandler
实现来配置拒绝策略。例如:
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
ExecutorService threadPool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
Executors.defaultThreadFactory(),
handler);
默认策略
默认情况下,如果没有指定 RejectedExecutionHandler
,ThreadPoolExecutor
会使用 AbortPolicy
。这种策略会在任务被拒绝时抛出 RejectedExecutionException
,通知调用者任务被拒绝。
总结
理解 ThreadPoolExecutor
提供的不同拒绝策略及其适用场景,可以帮助您更好地控制并发环境下的任务处理行为,确保程序在高负载和资源受限情况下依旧表现稳定。选择合适的拒绝策略对维护系统的可靠性和性能至关重要。