Java线程池拒绝执行异常:详解RejectedExecutionException
在Java并发编程中,java.util.concurrent.RejectedExecutionException 异常是线程池处理任务能力饱和时常见的报错。本文将通过一个实际案例,深入分析该异常的成因,并提出相应的解决方案。
案例描述:用户使用了一个线程池,其核心线程数和最大线程数均设置为 processNum * 10,阻塞队列为容量10000的LinkedBlockingQueue,拒绝策略为AbortPolicy。运行一段时间后,线程池状态为:pool size = 160, active threads = 160, queued tasks = 10000, completed tasks = 588179 时,抛出RejectedExecutionException。重启服务器后,当completed tasks 达到相同数量时,异常再次出现。
根本原因:异常并非线程池参数配置错误,而是AbortPolicy 拒绝策略导致的。当所有线程繁忙,且队列已满时,新任务无法被接受,AbortPolicy 直接抛出异常。 completed tasks 的数值只是异常发生时的状态,并非问题根源。 真正的核心问题在于:任务提交速度持续超过线程池的处理速度。
立即学习“Java免费学习笔记(深入)”;
解决方案:
-
性能分析: 首先,必须仔细分析应用的任务提交速率和线程池的处理能力。如果提交速率过高,需要优化代码,减少不必要的任务提交。
-
调整线程池参数: 可以考虑增加corePoolSize 和 maximumPoolSize,提升线程池的并发处理能力。但需谨慎,过大的线程数可能导致资源竞争加剧。
-
更换拒绝策略: AbortPolicy 策略过于直接,建议更换为更温和的策略:
- CallerRunsPolicy: 提交任务的线程直接执行该任务,降低提交速率。
- DiscardPolicy: 直接丢弃新任务,适用于对任务丢失容忍度较高的场景。
- DiscardOldestPolicy: 丢弃队列中最旧的任务,再尝试提交新任务。
选择合适的拒绝策略需要根据实际业务场景和对任务丢失的容忍度进行权衡。
总结:解决RejectedExecutionException 的关键在于平衡任务提交速率和线程池的处理能力,并选择合适的拒绝策略。 通过性能分析、参数调整和策略优化,可以有效避免该异常的发生。
以上就是java线程池拒绝执行异常: