ThreadPoolExecutor
タスクを実行するためにを使用し ています。バックエンドは、SynchronousQueue
であるため、エグゼキュータがすでにタスクを実行している場合は、をスローし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) {
}
}
}
}
予想される動作は次のとおりです。ワーカーを実行し、1秒間スリープした後、i(ワーカーがこれまでに実行された頻度を表す)とワーカーが作成されてからのミリ秒数を出力します。だから私は期待しています:
1 1015
2 2015
3 3016
4 4017
これはしばらくは問題なく動作しますが、ほぼ1時間後には次のようになります。
2919 2922196
2920 2942951
2921 2990407
したがって、あるワーカーの実行から次のワーカーの実行までの時間は、20秒(2919-> 2920)および38秒(2920-> 2921)などになります。すべてが非常に遅くなり、jvmはガベージコレクションに多くの時間を費やします。最後に(数日後)OutOfMemoryErrorが発生しました。
64ビットLinuxマシン上のOracleのJVM1.7.0_07で、これを-Xmx8M(ヒープスペースが増えると効果がかなり後で現れると思います)で実行しています。ポインタをいただければ幸いですが、おそらく私は明らかなことを見逃しているだけです。