一 发现RejectedExecutionException错误
今天查看服务器的时候发现了一些java.util.concurrent.RejectedExecutionException错误,这个是由于线程池里的线程忙不过来报出的。如下图:
像这种 RejectedExecutionException 错误,表明在Java应用程序中,一个任务尝试提交到线程池(ThreadPoolExecutor
)去执行时被拒绝了,具体原因是线程池达到了其配置的容量限制,无法接纳更多的任务。下面是错误信息的详细解析:
从上图可以看到以下线程池信息:
Running
- 线程池当前处于运行状态。pool size = 100
- 线程池配置的最大线程数为100,意味着它可以同时运行最多100个线程来处理任务。active threads = 100
- 当前有100个线程正在活跃地执行任务,即所有的工作线程都在使用中。queued tasks = 1000
- 任务队列的大小为1000,这意味着当所有线程都在使用时,额外的任务可以排队等待执行,但显然这个队列也已经满了。completed tasks = 253
- 已经有253个任务在这个线程池中完成了执行。
查看报错时间点的cpu运行状态:
从cpu反映来看突然上升而且持续很短,这是由于更新了队列服务器信息一下全部涌过来,很多状态信息是重复的而且变化时间一般十几分钟,大多数信息基本是同样的状态可以忽略不处理,所以这个错误在这种业务环境下是不影响业务,也可以忽略不调整的。但也可以通过调整以下线程池参数优化掉这个错误。
三 解决错误(线程池参数调整)
1. 增加线程池的核心线程数或最大线程数
- 核心线程数 (
corePoolSize
): 这些线程即使在空闲时也不会被销毁,增加核心线程数可以让更多的任务直接开始执行而不是等待。 - 最大线程数 (
maximumPoolSize
): 设置更高的最大线程数可以容纳更多的并发任务,但也要注意不要设置得太高,以免耗尽系统资源。
2. 调整任务队列的容量
- 如果你的应用能够容忍一定的延时,增大任务队列的大小可以让更多的任务排队等待执行,而不是直接被拒绝。但这也可能会增加任务的响应时间。
3. 更改拒绝策略
- Java的
ThreadPoolExecutor
允许你自定义任务拒绝时的行为。默认情况下,当队列已满且线程数达到最大时,会使用AbortPolicy
策略,直接抛出RejectedExecutionException
。你可以改为:CallerRunsPolicy
: 让调用者所在的线程直接执行任务,这可能会影响主线程的性能。DiscardPolicy
: 直接丢弃任务,不执行也不抛出异常。适用于可丢弃的任务。DiscardOldestPolicy
: 丢弃队列中最旧的任务,然后尝试重新提交被拒绝的任务。适用于任务执行顺序不敏感的情况。- 自定义策略:根据应用需求实现自己的
RejectedExecutionHandler
。