1. 线程池拒绝策略的本质与场景
当面试官抛出"线程池拒绝策略有哪些"这个问题时,实际上是在考察你对资源管理的系统化思考能力。线程池作为Java并发编程的核心组件,其拒绝策略直接决定了系统在过载情况下的行为模式。想象一下这样的场景:一个电商系统在大促期间,瞬时请求量暴涨到线程池队列的承载极限,此时新来的请求该如何处理?是直接丢弃?还是让调用者自己处理?不同的选择会导致完全不同的系统表现。
线程池的拒绝策略(RejectedExecutionHandler)本质上是一种系统保护机制。当线程池的工作线程已全部忙碌且任务队列达到容量上限时,新提交的任务就会触发拒绝策略。这种设计体现了"快速失败"(fail-fast)的思想——与其让任务无限制堆积导致内存溢出,不如明确拒绝并提供可控的降级方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 四种内置拒绝策略深度解析
2.1 AbortPolicy:默认的严格策略
这是ThreadPoolExecutor的默认策略,也是最严格的一种处理方式。当线程池无法接受新任务时,它会直接抛出RejectedExecutionException异常。这种"硬拒绝"的方式看似粗暴,但在很多场景下反而是最合理的:
java复制ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 2, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
new ThreadPoolExecutor.AbortPolicy() // 显式指定策略
);
// 当提交第5个任务时(2个活跃线程 + 2个队列任务)
executor.execute(() -> {
try { Thread.sleep(1000); }
catch (InterruptedException e) { e.printStackTrace(); }
}); // 此处抛出异常
关键经验:生产环境中使用AbortPolicy时,一定要在外层代码捕获RejectedExecutionException并实现降级逻辑,比如:
- 记录任务详情到死信队列
- 返回友好的用户提示
- 触发告警通知运维人员
2.2 CallerRunsPolicy:调用者执行策略
这个策略的名字直白地体现了它的行为——让提交任务的线程自己执行该任务。当线程池饱和时,新任务不会进入队列,而是由调用execute方法的线程直接运行:
java复制ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 2, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
new ThreadPoolExecutor.CallerRunsPolicy()
);
// 主线程
