Reputation: 87
I don't fully understand, how I should implement an ExecutorService in an application with occasionally upcoming tasks. Each task runs about 15minutes (simetimes longer). Sometimes there are 10 tasks a day and sometimes there is none for a whole week.
So, after executing some tasks if there is no task left in the queue, I want to shutdown the executor as it is not needed anymore and so that the garbage collector can to its job. After calling shutdown, no new tasks are queued to the executor.
Now, my problem is that I have to make sure that all tasks are done. That means, after calling shutdown, I have to make sure that a new Executor Service is instantiated before I submit the new task. I have to wait untill the old Executor Service is shut down (or terminated?) and init a new one. How should I implement this?
This is my approach:
// sync block to check for each task if a new Executor Service has to be created before submitting the task
synchronized (this) {
// do I have to check both isSutdown and isTerminated?
if (null == businessTaskExecutor || businessTaskExecutor.isShutdown() || businessTaskExecutor.isTerminated()) {
// simply init a new one
businessTaskExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
} else if (businessTaskExecutor.isTerminating()) {
// the termination process has started and is not done.
// Do I have to wait for the old executor or can I simply init a new one without waiting?
while (!businessTaskExecutor.isTerminated()) { }
businessTaskExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
}
}
Future<?> future = businessTaskExecutor.submit(() -> new BusinessTaskRunnable(businessTask));
if (future.isDone() && businessTaskExecutor.getQueue().isEmpty()) {
businessTaskExecutor.shutdown();
try {
if (!businessTaskExecutor.awaitTermination(1, TimeUnit.HOURS)) {
businessTaskExecutor.shutdownNow();
}
} catch (InterruptedException ex) {
businessTaskExecutor.shutdownNow();
Thread.currentThread().interrupt();
}
}
Explanation:
If the executor is null/shutdown/terminated, I init a new one, so far so good. Elseif the executor is currently terminating (because shutdown was called) no further tasks would be accepted by the executor. So I wait until it is terminated and then init a new one. After that I submit my task ... I only shutdown the executor, if no further tasks are in the queue. Despite I wait an hour as there stil could be a running task.
Is there a better implementation of the behaviour I wish?
Additional information: I use the ThreadPoolExecutor as I need getQueue() to check if it is empty. I could also use any other kind of Executor Service in different implementations.
Thanks in advance.
Upvotes: 1
Views: 289
Reputation: 73578
I want to shutdown the executor as it is not needed anymore and so that the garbage collector can to its job.
But it is needed, which is why you'll be recreating it. The GC can do it's job regardless of whether the executor is shut down or not (unless you've managed to create something very special with for example ThreadLocal
that would tie objects to the executor somehow).
I read that the garbage collector will only be invoked if I shut the executor down.
You either remember wrong or you were reading bad information.
Since you're running with a single thread, you don't really even need to worry about the pool configuration. A single long lived Executors.newFixedThreadPool(1);
is all you need.
In case you do need to free resources, you could configure core pool size with something like a new ThreadPoolExecutor(0, 1, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<BusinessTaskRunnable>());
. But that's irrelevant micro-optimization, one thread shouldn't make a difference.
Upvotes: 2