java.util.concurrent.RejectedExecutionException异常分析

感谢:https://blog.csdn.net/wzy_1988/article/details/38922449

核心池和最大池的大小

无界值

有界值

相同

不同

x < corePoolSize

corePoolSize < x < maximumPoolSize

提交新任务

maximumPoolSize设置为
无界值
(例如:Integer.MAX_VALUE)

允许线程池适应任意数量的并发任务

corePoolSize 和
maximumPoolSize相同

创建了固定大小的线程池

运行的线程数:x

创建新线程来处理请求,即使其他辅助线程是空闲的

仅当队列满时才创建新的线程

保持活动时间

如果池中当前有多于corePoolSize的线程,则这些多出的线程在空闲时间超过keepAliveTime时将会终止。

排队

所有BlockingQueue都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:

x < corePoolSize

x >= corePoolSize

成功

失败

成功

失败

运行的线程数:x

提交任务

Executor始终首选添加新的线程,而不进行排队

Executor始终首选将请求加入队列,而不添加新的线程

将请求加入队列

队列+1

创建新的线程

线程+1

创建此线程超出maximumPoolSize,任务将被拒绝(抛出RejectedExecutionException)

排队有三种通用策略:

  1. 直接提交:工作队列的默认选项是synchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界maximumPoolSizes以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增加的可能性。

  2. 无界队列:使用无界队列(例如,不具有预定义容量的LinkedBlockingQueue)将导致在所有corePoolSize线程都忙时新任务在队列中等待。这样,创建的线程就不会超过corePoolSize(因此,maximumPoolSize的值也就无效了)。

  3. 有界队列:当使用有限的maximumPoolSizes时,有界队列(如ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折中:使用大型队列和小型池可以最大限度的降低CPU使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞,则系统可能为超过您许可的更多线程安排时间,使用小型队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销,这样可会降低吞吐量。

终止

程序不再引用的池没有剩余线程会自动shutdown。如果希望确保回收取消引用的池(即使用户忘记调用shutdown()),则必须安排未使用的线程最终终止。

异常原因

  1. 线程池显示的调用了shutdown()之后,再向线程池提交任务的时候,如果你配置的拒绝策略是ThreadPoolExecutor.AbortPolicy的话,这个异常就被会抛出来。

  2. 当你的排队策略为有界队列,并且配置的拒绝策略是ThreadPoolExecutor.AbortPolicy,当线程池的线程数量已经达到了maximumPoolSize的时候,你再向它提交任务,就会抛出ThreadPoolExecutor.AbortPolicy异常。

解决方案

  1. 尽量调大maximumPoolSize,例如设置为Integer.MAX_VALUE
  2. 使用其他排队策略,例如LinkedBlockingQueue
  3. 调大队列(ArrayBlockingQueue)的大小
posted @   喵师傅  阅读(269)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示