ThreadPoolExecutor活跃线程为0时抛出RejectedExecutionException的原因排查
问题
我使用ThreadPoolExecutor创建了如下线程池:
executor = new ThreadPoolExecutor(4, 10, 10000000, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(1));
并通过如下代码读取GZIP文件提交任务:
try { GZIPInputStream gzipIS = new GZIPInputStream(new FileInputStream("filePath")); BufferedReader reader = new BufferedReader(new InputStreamReader(gzipIS, Charset.forName("UTF-8"))); String line = null; while ((line = reader.readLine()) != null) { executor.execute(new ParallelScan(line)); } } catch (Exception e) { System.out.printf("Exception == " + e); }
线程池最大线程数设为10,但在活跃线程数为0时仍抛出异常:
java.util.concurrent.RejectedExecutionException: java.util.concurrent.ThreadPoolExecutor@33990a0c[Running, pool size = 10, active threads = 0, queued tasks = 0, completed tasks = 23]
已知execute抛出该异常的两种常见原因:1.队列已满无法添加任务;2.线程池已关闭,但这两种情况均不适用,请问异常原因是什么?
分析与解答
这个异常的核心原因是线程池的饱和策略触发逻辑,结合配置参数拆解如下:
- 你的线程池参数:核心线程数4,最大线程数10,队列是容量仅为1的
ArrayBlockingQueue。 - 线程池处理任务的优先级逻辑:先创建核心线程(最多4个)→ 核心线程满后任务入队(最多1个)→ 队列满后创建非核心线程(最多到10个)→ 线程数达最大且队列满时触发饱和拒绝。
异常信息显示的pool size=10, active threads=0是异常抛出后的线程池状态,而非触发拒绝的瞬间状态:
当任务提交速度远快于线程处理速度时,会短暂出现“线程数已达10、队列已满”的临界状态,此时提交新任务直接触发拒绝策略;等异常信息输出时,之前的任务已经处理完成,线程回到空闲状态,就出现了活跃线程为0的情况。
另外你设置的空闲线程存活时间长达10000000分钟,空闲线程几乎不会被回收,线程数到达10后会一直维持这个规模,后续只要任务提交速度超过处理速度导致队列满,就会触发拒绝,哪怕之后线程又空闲下来。
内容的提问来源于stack exchange,提问作者Mounika
相关产品推荐
相关产品推荐

