Unfortunately the solution is flawed. There is a sort of bug with ScheduledThreadPoolExecutor
, also reported in this question: cancelling a submitted task does not fully release the memory resources associated with the task; the resources are released only when the task expires.
If you therefore create a TimeoutThreadPoolExecutor
with a fairly long expiration time (a typical usage), and submit tasks fast enough, you end up filling the memory - even though the tasks actually completed successfully.
You can see the problem with the following (very crude) test program:
public static void main(String[] args) throws InterruptedException {
ExecutorService service = new TimeoutThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(), 10, TimeUnit.MINUTES);
//ExecutorService service = Executors.newFixedThreadPool(1);
try {
final AtomicInteger counter = new AtomicInteger();
for (long i = 0; i < 10000000; i++) {
service.submit(new Runnable() {
@Override
public void run() {
counter.incrementAndGet();
}
});
if (i % 10000 == 0) {
System.out.println(i + "/" + counter.get());
while (i > counter.get()) {
Thread.sleep(10);
}
}
}
} finally {
service.shutdown();
}
}
The program exhausts the available memory, although it waits for the spawned Runnable
s to complete.
I though about this for a while, but unfortunately I could not come up with a good solution.
EDIT: I found out this issue was reported as JDK bug 6602600, and appears to have been fixed very recently.