RejectedExecutionException 分析
当往一个固定队列ArrayBlockingQueue 不停的提交任务时,会发生什么?
请看如下代码
private static final int QUEUE_SIZE = 20;
private static final int CORE_POOL_SIZE = 2;
private static final int MAX_POOL_SIZE = 2;
private static final int KEEP_ALIVE_TIME = 5; public static void main(String[] args) throws Exception {
ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(QUEUE_SIZE));
while(true) {
SenderTask st = new SenderTask();
executor.submit(st);
}
}
run完后会发生如下异常:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@b99f7c6 rejected from java.util.concurrent.ThreadPoolExecutor@2959ee1d[Running, pool size = 2, active threads = 2, queued tasks = 20, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:110)
如果你有研究过executor的源码你将发现,每次在submit任务的时候,会先进行addWorker()的判断,如果不能添加成功,则会抛出RejectedExecutionException
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
以上这个异常还有一种出现的情况就是,当你执行完execute.shutdown()后,任然往executor里提交task,也会抛出该异常
示例代码如下:
public class RejectedExecutionExceptionExample {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15));
Worker tasks[] = new Worker[20];
for(int i=0; i<20; i++){
tasks[i] = new Worker(i);
executor.execute(tasks[i]);
}
executor.shutdown();
executor.execute(tasks[0]);//继续执行任务
}
}
如何解决呢?
1. 控制提交的任务数量,即提交的任务数量不要超过它当前能处理的能力 (这里可以用生产者消费者的模式来解决)
2. 确保不要在shutdown()之后在执行任务
3. 可以用LinkedBlockingQueue代替ArrayBlockingQueue,因为LinkedBlockingQueue可以设成无界的,但是需要注意,设成无界后最终可能发生OOM(内存溢出),
所以要保证第一二点。
参考文献:https://examples.javacodegeeks.com/core-java/util/concurrent/rejectedexecutionexception/java-util-concurrent-rejectedexecutionexception-how-to-solve-rejectedexecutionexception/
RejectedExecutionException 分析的更多相关文章
- Java并发(五)线程池使用番外-分析RejectedExecutionException异常
目录 一.入门示例 二.异常场景1 三.异常场景2 四.解决方法 之前在使用线程池的时候,出现了 java.util.concurrent.RejectedExecutionException ,原因 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)
一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...
- tomcat源码分析(三)一次http请求的旅行-从Socket说起
p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...
- 线程池ThreadPoolExecutor、Executors参数详解与源代码分析
欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. ThreadPoolExecutor数据成员 Private final Atom ...
- JAVA线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提 ...
- [转]ThreadPoolExecutor线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第 ...
- Java线程池使用和分析(二) - execute()原理
相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的 ...
- java线程池ThreadPoolExector源码分析
java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...
随机推荐
- ZOJ 3931 Exact Compression
题目看了半小时才看懂的. 题意:首先根据给出的序列,构造出哈夫曼树,构造出来的是一棵二叉树,每个节点都有一个权值,每个节点的两个儿子只能取一个,问能否使取出来的节点权值之和刚好等于e. 这样一分析就很 ...
- Java Base64、AES、SHA1、MD5加密算法(转载)
package com.example.decript; import java.io.UnsupportedEncodingException; import java.security.Inval ...
- MySQL数据文件的导入、导出
1.导出整个数据库 mysqldump -u 用户名 -p 数据库名 > 导出的文件名 mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql 2.导 ...
- iOS强制切换横屏、竖屏
切换横竖屏最直接的方式是调用device的setOrientation方法.但是从sdk3.0以后,这个方法转为似有API,如果要上AppStore的话,要慎用! if ([[UIDevice cur ...
- DOM:文档对象模型 --树模型
文档:标签文档,对象:文档中每个元素对象,模型:抽象化的东西 一:window: 属性(值或者子对象):opener:打开当前窗口的源窗口,如果当前窗口是首次启动浏览器打开的,则opener是null ...
- IOS 7 Xcode 5 免IDP证书 真机调试(转载)
最近转开发了,真的很久没有更新博客了,今天有空写一篇吧. 今天带来的是 IOS 7 Xcode 5 免IDP证书的真机调试.说白了就是穷,不想给苹果交那$99的钱. 注意:虽然可以用这个方法实现真机调 ...
- R语言实战(五)方差分析与功效分析
本文对应<R语言实战>第9章:方差分析:第10章:功效分析 ================================================================ ...
- C# .NET修改注册表
c#修改注册表,需要引用Microsoft.Win32命名空间 using Microsoft.Win32; //声明 ///引用 RegistryKey reg; reg = Registry.Cl ...
- 内网服务器启动报错UNEXPECTED INCONSISTENCY解决方法
一开始进入系统显示reboot and select proper boot device or insert boot media in selected boot device and press ...
- Eclipse配置Git发布项目到Github
很牛叉的博客http://blog.csdn.net/luckarecs/article/details/7427605 一.安装插件 菜单栏Help --> Install New Softw ...