可能是RejectedExecutionException的原因

jpp*_*ade 62 java multithreading

我在我的tomcat服务器上获得此异常(+ liferay)

java.util.concurrent.RejectedExecutionException
Run Code Online (Sandbox Code Playgroud)

我的课就是这样的:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

我在行上遇到此异常super.execute(command); 当队列已满但LinkedBlockingQueue大小为2 ^ 31时,可能会发生此错误,我确信没有这么多命令等待.

一开始一切都很稳定,但在重新部署战争之后它就开始了.这个类不是战争的一部分,而是在tomcat/lib的jar中.

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

Sto*_*ica 71

来自ThreadPoolExecutor JavaDoc

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

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

可以定义和使用其他RejectedExecutionHandler类.这样做需要一些小心,特别是当策略设计为仅在特定容量或排队策略下工作时.

因此,据推测,重新加载战争会导致关闭战争Executor.尝试将相关的库放入战争中,以便Tomcat ClassLoader有更好的机会正确地重新加载你的应用程序.

  • 答案的最后一部分是一个不错的答案。 (2认同)
  • @AgiHammerthief 睡眠不是必需的,但适当的并发控制是必需的。此外,虽然您的“解决方案”可能会阻止崩溃,但它只是隐藏了听起来像是一个很大的资源所有权问题。 (2认同)

rus*_*tyx 6

只是为了增加OrangeDog的出色答案,an的约定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;
    }

}
Run Code Online (Sandbox Code Playgroud)

这实质上实现了背压算法,每当执行程序饱和时,都会降低生产者的速度。

用作:

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);
Run Code Online (Sandbox Code Playgroud)