Failing to call shutdown()
on a thread executor will result in a never terminating application.
Best practice to shut down the ExecutorService is this:
ExecutorService service = null;
try {
service = Executors.newSingleThreadExecutor();
// add tasks to thread executor
…
} finally {
if (service != null) service.shutdown();
}
Since Java knows the try-with-resources concept, wouldn't it be nice if we could do this?
try (service = Executors.newSingleThreadExecutor())
{
// add tasks to thread executor
…
}
Since the ExecutorService class does not implement the AutoCloseable interface, we need to wrap it with something that does. Then, we call the ExecutorService. shutdown method within the close method from the AutoCloseable interface. If we don't implement the AutoCloseable interface, we'll get compile-time errors.
The Runnable interface represents a task that can be executed concurrently by a thread or an ExecutorService . The Callable can only be executed by an ExecutorService.
Closeable extends IOException whereas AutoCloseable extends Exception. Closeable interface is idempotent (calling close() method more than once does not have any side effects) whereas AutoCloseable does not provide this feature. AutoCloseable was specially introduced to work with try-with-resources statements.
That ExecutorService has actually two shutdown-related methods; based on the simple fact that both ways of shutting down a service make sense.
Thus: how would you auto-close a service then? In a consistent manner that works for everybody?!
So, the reasonable explanation in my eyes: you can't make an ExecutorService a AutoClosable because that service does not have a single "close" like operation; but two!
And if you think you could make good use of such an auto-closing service, writing up your own implementation using "delegation" would be a 5 minute thing! Or probably 10 minutes, because you would create one version calling shutdown()
as close operation; and one that does shutdownNow()
instead.
This is a mediocre workaround
ExecutorService service = Executors.newSingleThreadExecutor();
try (Closeable close = service::shutdown) {
}
Or, if the checked exception bothers you, you could write:
interface MyCloseable extends AutoCloseable {
void close();
}
And then
ExecutorService service = Executors.newSingleThreadExecutor();
try (MyCloseable close = service::shutdown) {
}
Of course, you must never ever put anything between the assignment and the try
statement, nor use the service
local variable after the try
statement.
Given the caveats, just use finally
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With