8

我正在使用 a ThreadPoolExecutor来运行任务。后端是 a SynchronousQueue,所以如果 executor 已经在执行任务,它会抛出RejectedExecutionException. 这是一个简单的测试用例:

public class ExecutorTest {

  final static Worker worker = new Worker();

  public static void main(String[] args) {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());

    while (true) {
        try {                
            executor.execute(worker);                
        }catch (RejectedExecutionException e) {                
        }
    }        
  }

  static class Worker implements Runnable {

    private int i = 0;
    private long start = System.currentTimeMillis();

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println(++i + " " + (System.currentTimeMillis() - start));
        } catch (InterruptedException ex) {                
        }
    }
  }
}

预期的行为是:执行 worker 并在休眠一秒钟后,打印出 i(表示到目前为止执行 worker 的频率)和自 worker 创建以来的毫秒数。所以我期待:

1 1015 
2 2015
3 3016 
4 4017

这在一段时间内工作正常,但几乎在一个小时后:

2919 2922196
2920 2942951
2921 2990407

所以一个worker执行和下一个worker执行之间的时间是20秒(2919->2920)和38秒(2920->2921)等等。一切都变得非常缓慢,jvm 在垃圾收集上花费了大量时间。最后(几天后)我遇到了 OutOfMemoryError。

我在 64 位 Linux 机器上的 Oracle JVM 1.7.0_07 上使用 -Xmx8M 运行它(我假设效果会在更多堆空间后出现)。我会很感激任何指示,但可能我只是错过了显而易见的事情。

4

1 回答 1

2

您可以尝试修改ThreadPoolExecutor实例化。您只需向构造函数添加一个参数即可使用RejectExecutionHandler将默默丢弃被拒绝任务的 a 。

public static void main(String[] args) {
  ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());

  while (true) {
    executor.execute(worker);                
  }
}

因此,如果您的问题来自重复RejectedExecutionException(我认为是这样),您将避免它。

于 2012-10-16T13:17:28.427 回答