我在tomcat服务器上发现了这个异常(+ liferay)
java.util.concurrent.RejectedExecutionException
我的课就是这样:
public class SingleExecutor extends ThreadPoolExecutor {
public SingleExecutor(){
super(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
@Override
public void execute(Runnable command) {
if(command instanceof AccessLogInsert){
AccessLogInsert ali = (AccessLogInsert)command;
ali.setConn(conn);
ali.setPs(ps);
}
super.execute(command);
}
}
我在super.execute(command);
行上遇到此异常
当队列已满但LinkedBlockingQueue
大小为2 ^ 31时,可能会发生此错误,并且我确信没有这么多命令等待。
一开始一切都很稳定,但在我重新部署战争之后它就开始了。这个类不是战争的一部分,而是在tomcat / lib的jar中。
你知道为什么会发生这种情况以及如何解决这个问题吗?
答案 0 :(得分:63)
来自ThreadPoolExecutor JavaDoc
当
execute(java.lang.Runnable)
关闭时,以及Executor
对最大线程和工作队列容量使用有限边界时,将拒绝方法Executor
中提交的新任务,以及已经饱和了。在任何一种情况下,execute方法都会调用其RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor)
的{{1}}方法。提供了四种预定义的处理程序策略:
- 在默认的
RejectedExecutionHandler
中,处理程序在拒绝时会抛出运行时ThreadPoolExecutor.AbortPolicy
。- 在
RejectedExecutionException
中,调用execute本身的线程运行任务。这提供了一种简单的反馈控制机制,可以降低新任务的提交速度。- 在
ThreadPoolExecutor.CallerRunsPolicy
中,简单地删除了无法执行的任务。- 在
醇>ThreadPoolExecutor.DiscardPolicy
中,如果执行程序未关闭,则删除工作队列头部的任务,然后重试执行(可能会再次失败,导致重复执行。)可以定义和使用其他类型的
ThreadPoolExecutor.DiscardOldestPolicy
类。这样做需要一些小心,特别是当策略被设计为仅在特定容量或排队策略下工作时。
因此,据推测,重新加载战争会触发RejectedExecutionHandler
的关闭。尝试将相关的库放入战争中,以便Tomcat的Executor
更有可能正确地重新加载你的应用程序。
答案 1 :(得分:5)
除了增加OrangeDog的出色答案外,Executor
的约定确实如此,以使执行者饱和时,其execute
方法将抛出RejectedExecutionException
(即,执行器中没有空间)队列)。
但是,如果它阻塞,它会自动等待直到队列中有足够的空间来执行新任务,这将很有用。
使用以下自定义BlockingQueue
可以实现:
public final class ThreadPoolQueue extends ArrayBlockingQueue<Runnable> {
public ThreadPoolQueue(int capacity) {
super(capacity);
}
@Override
public boolean offer(Runnable e) {
try {
put(e);
} catch (InterruptedException e1) {
return false;
}
return true;
}
}
这实质上实现了反压算法,每当执行程序饱和时,都会减慢生产者的速度。
用作:
int n = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, n, 1, TimeUnit.MINUTES, new ThreadPoolQueue(n));
for (Runnable task : tasks) {
executor.execute(task); // will never throw, nor will queue more than n tasks
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.HOURS);