Reputation: 1469
Say i've got the following code:
public void run(){
while (true){
function1();
...
functionN();
}
}
And i wanna exit 'gracefully' - Which means for me that once i sent a shutdown signal and currently the thread is at functionK(), The thread will 'break' the loop and exit run.
So i've tried using Thread.interrupt() like this:
public void run(){
while (true){
try {
function1();
...
functionN();
} catch (InterruptedException ex) {
/* Cleanup and exit. */
}
}
}
But this doesn't work - The thread continutes to run endlessly even with interrupt flag on.
Just for the record:
public void run(){
while (!thread.isInterrupted()){
try {
function1();
...
functionN();
} catch (InterruptedException ex) {
/* Cleanup and exit. */
}
}
}
Stops the loop, But doesn't help me. Since each function does something that might take several minutes and there are a lot of different function so checking before each function whether interrupted flag is one might be costly (Especially since most of the times the application runs smoothly).
I wonder whether there is a special mechanism i can use for that kind of problem.
Upvotes: 2
Views: 2327
Reputation: 251
Actually if you are doing CPU bound work in your methods, you have to check for Thread.interrupted()
by yourself and throw InterruptedException
yourself. Java won't magically do it for you, unless you park at some specifically designed spaces, such as Semaphore.wait()
etc.
Upvotes: 3
Reputation: 4015
As stated in the book "Java concurrency in Practice" :"Java does not provide any mechanism for safely forcing a thread to stop what is doing", so you must implement something on your side. checking the interrupted flag and handling the InterruptedException is the best way to manage thread cancellation. If one of you function1()...functionN() is in the middle of a database transaction or a HTTP call is up to your program to handle the cancellation; you can wait until to n seconds and save the current state or cancel the transaction and roolback, the action to perform is dictated by your application logic.
Upvotes: 2
Reputation: 49754
The API documentation is very clear about this:
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
So you can only rely on this exception if you're waiting for object monitors. There are a couple of other exceptions thrown by certain I/O operations but if you don't use them either, there is no other option than to check the interrupted()
flag.
What you can do though is to re-organise your code: if you've got N
methods that are called one after the other, is it not possible to abstract them out into a loop? More often than not it is possible to find a way to refactor code to support interruption, the exact way depends on your actual scenario. My first question would be: why does a single method run for minutes? That sounds a bit fishy (though it may be justified).
Either way, interruptibility isn't something that comes for free, you have to actively design interruption points if you want your code to be more responsive to interruption than the length of the main loop.
One more thing though: checking the interrupted()
flag is most definitely NOT costly. Not when you spend minutes in your main loop, and it's a lot cheaper than constructing and handling an exception. I'd go as far as to say that you'll find very few things faster than a call to Thread.isInterrupted()
.
Upvotes: 4
Reputation: 140319
Your second example will keep looping after the interrupt. This is because InterruptedException
doesn't actually mean that the Thread's interrupted flag is set; in fact, you don't need to check it at all.
To fix this, you can simply re-interrupt the thread (to allow callers to know that the thread was interrupted), and then break:
public void run(){
while (true) {
try {
function1();
//...
functionN();
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
}
}
}
Upvotes: 2