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
…
}
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) {
}
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.
I don't see where AutoCloseable is that useful for an Executor. try-with-resources is for things that can be initialized, used, and released within the scope of a method. This works great for things like files, network connections, jdbc resources, etc., where they get opened, used, and cleaned up quickly. But an executor, especially a threadpool, is something you want available for a long time period, probably over the lifetime of the application, and will tend to get injected into things like singleton services, which can have a method that the DI framework knows to call on application shutdown to clean up the executor. This usage pattern works fine without try-with-resources.
Also, a big motivator behind try-with-resources is making sure exceptions don't get masked. That's not a consideration so much with executors, all the exception-throwing will be happening in the tasks submitted to the executor,
exception-masking is not an issue.
Try-with-resources is about auto-closing of Readers/Streams, where as ExecutorService is about executing tasks using a pool of threads.
So I am not really sure if there is a parallel between the two that we can think of applying try-with-resources to ExecutorServices as well.
UPDATED
Quoting Java Language Specification:
A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block. catch clauses and a finally clause are often unnecessary when resources are closed automatically.
The spec calls the variables as "resources". So I am not sure if ExecutorService can be called as a resource and so do not think ExecutorService as a parallel to Readers/ Streams/ Statement/ ResultSet/ Connection etc.