Question:
How do I make a series of threads that have timed out with invokeAll
stop execution.
Background:
I have a list of callables
I want to wait to complete. However, if they don't complete within a set time (say a second) I want to cancel them. This seems easy enough with
executor.invokeAll(callables, 1000l, TimeUnit.MILLISECONDS);
So after a second it will time out just fine and I can go on with my day. However in the background the threads are still active and potentially executing some pieces of code. Essentially they are not interrupted which I do not want to happen - I want the threads to stop executing.
Is there any way to use the futures list returned to stop the threads after invokeAll
has hit its timeout?
ExecutorService
was designed to support cancellation of tasks that respond to interruption. So, the proper way to do this is by making your Callable
implementations notice that they've been interrupted.
If your task is purely computational, or if it loops frequently, calling a third-party library, this is easy. Somewhere in your task, you'll have a loop that looks something like:
while (!Thread.interrupted()) {
/* Keep going */
}
Of course, you might test other task-specific conditions in your loop too, but you should be testing the interrupted state of the current thread.
Calling interrupted()
will clear the interrupted status. Calling Thread.currentThread().isInterrupted()
will preserve the interrupted status. For worker threads in an ExecutorService
, keeping the interrupted status doesn't matter too much—the service is interrupting its own threads, and when its thread returns from your task, the service clears the status without looking at it. But, it's a good habit to adopt, so that your code will work well if it is incorporated in a task. To re-assert the interrupted status after catching an InterruptedException
or detecting it with Thread.interrupted()
, simply call Thread.currentThread().interrupt()
.
If the task is a long-running call to a third-party library that doesn't support interruption, or a blocking call to an uninterruptible I/O operation, your "task" is much more difficult. You may be out of luck altogether, or you might be able to find a kludge to abort the operation asynchronously.
For example, if you create a Socket
, and pass it (or its streams) to your task, you could asynchronously close the socket. If invokeAll
times out, the caller would need additional code to close the socket.
You can't have it both ways.
The ExecutorService "framework" allows you to only think in terms of Callable
objects and Future
results. This abstraction hides all the low level details of the threads involved. Thus: even if it would be possible, your idea would most likely be a "dirty hack".
In other words: if you want low-level, direct access to the threads doing something - then you might have to use your own "thread pooling" implementation.
Middle ground: keep in mind that these threads execute your Callable/Runnable instances. You could of course think up something where those objects regularly check some sort of "command queue". And when the queue contains a cancel request - then your code in the Callable stops doing its work.
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