Java线程池抛出异常 java.util.concurrent.RejectedExecutionException 是配置的问题吗?
异常内容如下
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 这个数字时抛异常,哪位大神有解决方案,求指教
回答:
这个异常是触发了线程池的拒绝策略导致的, 你需要大致了解一下线程池的线程调度逻辑。
线程池中有几个核心参数:
- 核心线程数(corePoolSize)
- 最大线程数(maximumPoolSize)
- 等待队列(BlockingQueue<Runnable> workQueue)
- 拒绝策略(RejectedExecutionHandler handler)。
提交的任务将先使用核心线程数, 但超过核心线程数, 则存入等待队列中, 当等待队列满了, 则创建小于等于最大线程数的线程执行任务, 当最大线程数也不足以容纳新的任务时将出发拒绝策略。
可用的拒绝策略有:
- ThreadPoolExecutor.AbortPolicy(默认):当线程池无法接受新任务时,抛出RejectedExecutionException异常,阻止任务提交。题主所触发的策略
- ThreadPoolExecutor.CallerRunsPolicy:当线程池无法接受新任务时,由提交任务的线程来执行被拒绝的任务。这种策略可以降低新任务的流量,但也可能导致整体性能下降。可以尝试使用的策略
- ThreadPoolExecutor.DiscardPolicy:当线程池无法接受新任务时,直接丢弃被拒绝的任务,没有任何异常抛出。
- ThreadPoolExecutor.DiscardOldestPolicy:当线程池无法接受新任务时,丢弃线程池队列中最旧的未处理任务,然后尝试重新提交被拒绝的任务。视业务场景可以使用的策略
回答:
目测不是配置问题,就是堆积的任务太多了处理不过来了
new LinkedBlockingQueue(10000) 最大积压10000个任务
new ThreadPoolExecutor.AbortPolicy() 积压满了就拒绝服务
解决方案:
- 观察任务积压情况,排查积压原因
改善积压情况
- 增加线程池大小
- 优化代码提高处理速度
提高容量
- 增加队列长度
- 增加更多服务实例
回答:
java.util.concurrent.RejectedExecutionException
这个异常是在任务无法由Executor
执行时抛出的。这通常是因为Executor
已经被关闭,或者因为它的任务队列已经满了。
回答:
这个帖子可以看看:https://blog.csdn.net/wzy_1988/article/details/38922449
解决方案:
尽量调大maximumPoolSize,例如设置为Integer.MAX_VALUE
public ExecutorService customerExecutorService = new ThreadPoolExecutor(3, Integer.MAX_VALUE, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
使用其他排队策略,例如LinkedBlockingQueue
<span style="white-space:pre"> </span>public ExecutorService customerExecutorService = new ThreadPoolExecutor(3, 5, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
回答:
1万的队列都扛不住,你的那些任务是有多耗时
- 如果cpu利用率还有空余,调大核心线程数,processNum * 50
- 如果cpu已经满了,只能优化你的任务逻辑,减少单次任务的耗时
- 如果任务无法优化,说明你的机器性能已经达到负载极限了,加机器
回答:
根据给出的内容,线程池还在running,但是pool已经满了(160),然后queue也满了(10000),所以新submit的task被abort策略拒绝了...
看比例,160运行:10000等待,说明单个任务执行时间太长了,处理不过来了...
每次都是 completed tasks = 588179 这个数字时抛异常
这可能说明你每个任务的执行时间都很恒定,所以导致每次到这个时候(588179+160+10000),线程池就满了。
我建议首先检查一下任务的处理逻辑,看看代码有没有什么问题(之前遇到过线程任务里面有大循环的,有sleep的,有互相锁数据的,有调用长耗时三方接口的),打日志,观察单个任务的执行时间,优化代码的耗时,或者从业务角度调整相关逻辑...
然后还可以加mq一类的消息队列做消费端接耦,实在不行就加资源,加线程,加硬件...
回答:
答案:根据你的线程池参数配置,抛出这个exception是正确的。抛异常原因是待处理任务数量到达了配置的10000个(new LinkedBlockingQueue(10000)),这时候再来一个待处理的任务,根据你配置的拒绝策略(new ThreadPoolExecutor.AbortPolicy()),这时候,就回抛出题中的异常。
解决办法:方向一:你这个任务明显是耗时任务,考虑加入mq或者数据库先把待处理的任务记录到db,慢慢处理,替换线程池的方案。
方向二:判断任务耗时是否正常,可否优化耗时时间,减少任务堆积。
以上是 Java线程池抛出异常 java.util.concurrent.RejectedExecutionException 是配置的问题吗? 的全部内容, 来源链接: utcz.com/p/945201.html