Thursday, 16 April 2015

Dealing with Interruptions

I was just watching the VJUG interview with Heinz Kabutz which inspired me to write a post about Interruptions. By the way I would recommend subscribing to the VJUG YouTube channel - very informative indeed.

Heinz is always good value and it's difficult to watch any of his presentations without learning a lot. He raised the topic of how to deal with an InterruptedException and postulated that few Java programmers deal correctly with it.  The best explanation of thread interruptions I've read is contained in my favourite book on Java - Java Concurrency In Practice (p138-144). If you've read these pages you will know how to deal with an InterruptedException correctly :-)

Here's a short summary:

How often have you come across this code:

.......
try {
   Thread.sleep(1000);
} catch(InterruptedException e){
   e.printStackTrace();
}
......

A process is required to sleep for a second but 'annoyingly' has to deal with an InterruptedException.  The developer doesn't really know what to do with this exception so just logs it to the console.

This is very bad practice! If you are sure that your thread will never be interrupted (you are writing this code in a closed system) then you should probably do something like throw an AssertionError in the catch block with a comment that this should never happen.  If it is at all possible that the thread might be interrupted then you need to deal with that interruption correctly.

A thread can be interrupted by calling its interrupt() method.  This will set its interrupt status to true and consequently when you call isInterrupted() will return true. When interrupt() is called certain blocking methods, like Thread.sleep() will throw an InterruptedException. Note that triggering the InterruptedException will set the interrupt status to false.  There is a method on Thread called interrupted() which like isInterrupted() returns the interrupt status of the thread but crucially sets the interrupt status back to false. (interrupted() is a very strangely named method for what it does...)

We can see all this at work in the following example:


To quote Java Concurrency in Practice:

"There is nothing in the API or language specification that ties interruption to any specific cancellation semantics, but in practice, using interruption for anything but cancellation is fragile and difficult to sustain in larger applications."

In other words an interrupt is just a signal. You could theoretically use the interrupt mechanism to instruct the thread to do anything you wanted, perhaps to take do action A instead of B - but we are counselled against it.

.......
try {
   Thread.sleep(1000);
} catch(InterruptedException e){
   actionA();
   return;
}
actionB();
......   

So what is the correct way to deal with an interrupt.  Well that depends a bit on your code. Let's assume we are using the interrupt 'correctly' as a cancellation and your code expects a cancellation to occur (this should be specified in the documentation) then your code should cancel its actions in a controlled manner.  Just because an exception is thrown does not means you have to exit in haste leaving a trial of mess behind you. Because you have dealt with the interrupt there is no need to restore the interrupt status on the thread. 

If you do not expect an interrupt then you should handle the interrupt gracefully (maybe finish what you are doing) and then restore the interruption on the thread for some code higher up the stack to deal with. Remember once the exception has been thrown the interrupt status is set to false. Here's the way (code taken from the book) as to how it should be done:

No comments:

Post a Comment