可能是RejectedExecutionException的原因

时间:2011-11-18 13:33:20

标签: java multithreading

我在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中。

你知道为什么会发生这种情况以及如何解决这个问题吗?

2 个答案:

答案 0 :(得分:63)

来自ThreadPoolExecutor JavaDoc

  

execute(java.lang.Runnable)关闭时,以及Executor对最大线程和工作队列容量使用有限边界时,将拒绝方法Executor中提交的新任务,以及已经饱和了。在任何一种情况下,execute方法都会调用其RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor)的{​​{1}}方法。提供了四种预定义的处理程序策略:

     
      
  1. 在默认的RejectedExecutionHandler中,处理程序在拒绝时会抛出运行时ThreadPoolExecutor.AbortPolicy
  2.   
  3. RejectedExecutionException中,调用execute本身的线程运行任务。这提供了一种简单的反馈控制机制,可以降低新任务的提交速度。
  4.   
  5. ThreadPoolExecutor.CallerRunsPolicy中,简单地删除了无法执行的任务。
  6.   
  7. ThreadPoolExecutor.DiscardPolicy中,如果执行程序未关闭,则删除工作队列头部的任务,然后重试执行(可能会再次失败,导致重复执行。)
  8.         

    可以定义和使用其他类型的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);