当前位置: 首页 > 知识库问答 >
问题:

有偿问答 Java线程池抛出异常 java.util.concurrent.RejectedExecutionException 是配置的问题吗?

严宇
2023-06-12

异常内容如下

java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@174a9357 rejected from java.util.concurrent.ThreadPoolExecutor@68ab7098[Running, pool size = 160, active threads = 160, queued tasks = 10000, completed tasks = 588179]
        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
        at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
        at com.test.TcpServerHandler.channelRead(TcpServerHandler.java:71)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)

线程池配置如下

new ThreadPoolExecutor(processNum * 10, processNum * 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(10000), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy())

服务器是8核16线程的

异常后重启一段时间还是会重现,每次都是 completed tasks = 588179 这个数字时抛异常,哪位大神有解决方案,求指教

共有7个答案

文喜
2023-06-12

答案:根据你的线程池参数配置,抛出这个exception是正确的。抛异常原因是待处理任务数量到达了配置的10000个(new LinkedBlockingQueue(10000)),这时候再来一个待处理的任务,根据你配置的拒绝策略(new ThreadPoolExecutor.AbortPolicy()),这时候,就回抛出题中的异常。
解决办法:方向一:你这个任务明显是耗时任务,考虑加入mq或者数据库先把待处理的任务记录到db,慢慢处理,替换线程池的方案。
方向二:判断任务耗时是否正常,可否优化耗时时间,减少任务堆积。

桓智敏
2023-06-12

根据给出的内容,线程池还在running,但是pool已经满了(160),然后queue也满了(10000),所以新submit的task被abort策略拒绝了...
看比例,160运行:10000等待,说明单个任务执行时间太长了,处理不过来了...

每次都是 completed tasks = 588179 这个数字时抛异常

这可能说明你每个任务的执行时间都很恒定,所以导致每次到这个时候(588179+160+10000),线程池就满了。
我建议首先检查一下任务的处理逻辑,看看代码有没有什么问题(之前遇到过线程任务里面有大循环的,有sleep的,有互相锁数据的,有调用长耗时三方接口的),打日志,观察单个任务的执行时间,优化代码的耗时,或者从业务角度调整相关逻辑...
然后还可以加mq一类的消息队列做消费端接耦,实在不行就加资源,加线程,加硬件...

景仲渊
2023-06-12

1万的队列都扛不住,你的那些任务是有多耗时

  • 如果cpu利用率还有空余,调大核心线程数,processNum * 50
  • 如果cpu已经满了,只能优化你的任务逻辑,减少单次任务的耗时
  • 如果任务无法优化,说明你的机器性能已经达到负载极限了,加机器
武元白
2023-06-12

这个帖子可以看看:https://blog.csdn.net/wzy_1988/article/details/38922449
解决方案:

  1. 尽量调大maximumPoolSize,例如设置为Integer.MAX_VALUE

    public ExecutorService customerExecutorService = new ThreadPoolExecutor(3, Integer.MAX_VALUE, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
  2. 使用其他排队策略,例如LinkedBlockingQueue

    <span style="white-space:pre">    </span>public ExecutorService customerExecutorService = new ThreadPoolExecutor(3, 5, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

    企业微信截图_1686216452442.png

贡英华
2023-06-12

java.util.concurrent.RejectedExecutionException这个异常是在任务无法由Executor执行时抛出的。这通常是因为Executor已经被关闭,或者因为它的任务队列已经满了。

万铭
2023-06-12

目测不是配置问题,就是堆积的任务太多了处理不过来了
new LinkedBlockingQueue(10000) 最大积压10000个任务
new ThreadPoolExecutor.AbortPolicy() 积压满了就拒绝服务
解决方案:

  1. 观察任务积压情况,排查积压原因
  2. 改善积压情况

    1. 增加线程池大小
    2. 优化代码提高处理速度
  3. 提高容量

    1. 增加队列长度
    2. 增加更多服务实例
乐正育
2023-06-12

这个异常是触发了线程池的拒绝策略导致的, 你需要大致了解一下线程池的线程调度逻辑。
线程池中有几个核心参数:

  1. 核心线程数(corePoolSize)
  2. 最大线程数(maximumPoolSize)
  3. 等待队列(BlockingQueue<Runnable> workQueue)
  4. 拒绝策略(RejectedExecutionHandler handler)。

提交的任务将先使用核心线程数, 但超过核心线程数, 则存入等待队列中, 当等待队列满了, 则创建小于等于最大线程数的线程执行任务, 当最大线程数也不足以容纳新的任务时将出发拒绝策略。
可用的拒绝策略有:

  1. ThreadPoolExecutor.AbortPolicy(默认):当线程池无法接受新任务时,抛出RejectedExecutionException异常,阻止任务提交。题主所触发的策略
  2. ThreadPoolExecutor.CallerRunsPolicy:当线程池无法接受新任务时,由提交任务的线程来执行被拒绝的任务。这种策略可以降低新任务的流量,但也可能导致整体性能下降。可以尝试使用的策略
  3. ThreadPoolExecutor.DiscardPolicy:当线程池无法接受新任务时,直接丢弃被拒绝的任务,没有任何异常抛出。
  4. ThreadPoolExecutor.DiscardOldestPolicy:当线程池无法接受新任务时,丢弃线程池队列中最旧的未处理任务,然后尝试重新提交被拒绝的任务。视业务场景可以使用的策略
 类似资料:
  • 本文向大家介绍Java线程池的几种实现方法及常见问题解答,包括了Java线程池的几种实现方法及常见问题解答的使用技巧和注意事项,需要的朋友参考一下 工作中,经常会涉及到线程。比如有些任务,经常会交与线程去异步执行。抑或服务端程序为每个请求单独建立一个线程处理任务。线程之外的,比如我们用的数据库连接。这些创建销毁或者打开关闭的操作,非常影响系统性能。所以,“池”的用处就凸显出来了。 1. 为什么要使

  • 问题内容: 我只是在查看Python FAQ,因为它是另一个问题中提到的。以前从未真正详细地研究过它,我遇到了一个问题:“例外情况有多快?”: try / except块非常有效。实际上捕获异常是昂贵的。在2.0之前的Python版本中,通常使用以下习惯用法: 我对 “捕获异常代价高昂”这一 部分感到有些惊讶。这是否仅是指您实际上将异常保存在变量中的情况,或者通常是所有s(包括上面示例中的一个)的

  • 抛出异常的行为是否可能抛出不同的异常? 为了抛出异常,必须(可选地)分配新对象,并调用其构造函数(隐式调用fillinstacktrace)。在某些情况下,听起来像addSupressed也被称为。那么如果没有足够的内存会发生什么呢?JVM是否需要预分配内置异常?例如,(1/0)会抛出OutOfMemoryError而不是ArithmeticException吗? 此外,构造函数是一个方法调用,因

  • 我试图用spring配置bitronix,但我在启动Tomcat时遇到了异常。 任何帮助都很感激。 原因:org.hibernate.engine.JNDI.jndiException:无法在org.hibernate.engine.JNDI.internal.jndiserviceimpl.locate(jndiserviceimpl.java:117)在org.hibernate.engine

  • 我有一个小问题,所以我一直在做这个程序,出于某种原因,它抛出了一个空指针异常。我已经让它工作了,但它不会显示我试图创建的JTable,只是一个空白窗口,当我包含代码时,它就会崩溃。。。。有什么想法吗?

  • 问题内容: 我目前正在使用play2框架。 我有几个正在抛出的类,但是play2s全局处理程序使用throwable而不是异常。 例如我的一门课是抛出一个。我是否可以检查可抛物体(如果是)? 问题答案: 您可以使用它来检查它是否存在。 例: 假设是参考。