Reputation: 6539
This code is permanently blocking on future.get()
. I would have expected a CancellationException
or an InterruptedException
. Can anyone explain this?
ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {/*squelch*/}
});
Future<Integer> future = es.submit(() -> 1);
es.shutdownNow();
try {
future.get();
} catch (ExecutionException e) {e.printStackTrace();}
The docs say there are no guarantees, but I still find the observed behaviour strange because it implies that failures to stop are caused by misbehaved threads. In this case there doesn't seem to be any attempt to stop the thread.
There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.
Upvotes: 3
Views: 1141
Reputation: 7576
In this case there doesn't seem to be any attempt to stop the thread.
It tries to stop running Runnables
. In this case, that's probably the one that's sleeping. It's going to be interrupted, and you'll catch the exception and return. The nop Runnable
is still in the queue.
You wouldn't get an InterruptedException
unless the thread calling future.get()
were interrupted.
CancellationException
would be reasonable to expect, except technically, you didn't cancel the Future, you shut down the executor.
The intended use seems to be that you retail the list of Runnables
shutdownNow()
returns so you can run them. That works, but you can't check them against what you've submitted because they've actually been decorated (but you don't know this, and it's kinda a surprise that it doesn't return the references you submitted).
There's two bad workarounds to get this functionality: track the futures you got back and cancel them yourself or cast the Runnables
that were returned by shutdownNow()
to Futures and cancel them, but that only works because that happens to be the internal implementation of the executor you're using.
So yes, that's the behavior, it's technically right, but it's a little weird. What are you trying to accomplish, here?
Upvotes: 3