我正在使用 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 运行它(我假设效果会在更多堆空间后出现)。我会很感激任何指示,但可能我只是错过了显而易见的事情。