Wednesday, 19 September 2012

Puzzle 84: Rudely Interrupted


In this program, a thread tries to interrupt itself and then checks whether it succeeded. What does the program print?
public class SelfInterruption {

    public static void main(String[] args) {

        Thread.currentThread().interrupt();



        if (Thread.interrupted()) {

            System.out.println("Interrupted: " +

                Thread.interrupted());

        } else {

            System.out.println("Not interrupted: " +

                Thread.interrupted());

        }

    }

}


Solution 84: Rudely Interrupted

Although it is not common for a thread to interrupt itself, it isn't unheard of, either. When a method catches an InterruptedException and is not prepared to deal with it, the method usually rethrows the exception. Because it is a checked exception, a method can rethrow it only if the method declaration permits. If not, the method can "reraise" the exception without rethrowing it, by interrupting the current thread. This works fine, so our program should have no trouble interrupting itself. Therefore, the program should take the first branch of the if statement and print Interrupted: true. If you ran the program, you found that it doesn't. It doesn't print Not interrupted: false, either; it prints Interrupted: false.
It looks as if the program can't make up its mind about whether the thread was interrupted. Of course, this makes no sense. What really happened was that the first invocation of THRead.interrupted returned true and cleared the interrupted status of the thread, so the second invocation—in the then branch of the if-then-else statement—returned false. Calling Thread.interrupted always clears the interrupted status of the current thread. The method name gives no hint of this behavior and, as of release 5.0, the one-sentence summary in the documentation is equally misleading: "Tests whether the current thread has been interrupted" [Java-API]. Therefore, it is understandable that many programmers are unaware that Thread.interrupted has any effect on the interrupted status of the thread.
The THRead class has two methods to query the interrupted status of a thread. The other one is an instance method named isInterrupted, and it does not clear the interrupted status of the thread. If rewritten to use this method, the program produces the expected output of Interrupted: true:
public class SelfInterruption {

    public static void main(String[] args) {

        Thread.currentThread().interrupt();



        if (Thread.currentThread().isInterrupted()) {

            System.out.println("Interrupted: " +

                Thread.currentThread().isInterrupted());

        } else {

            System.out.println("Not interrupted: " +

                Thread.currentThread().isInterrupted());

        }

    }

}


The lesson of this puzzle is: Don't use THRead.interrupted unless you want to clear the interrupted status of the current thread. If you just want to query it, use isInterrupted instead. The lesson for API designers is that methods should have names that describe their primary functions. Given the behavior of THRead.interrupted, it should have been named clearInterruptStatus. Its return value is secondary to the state change it effects. Especially when a method has a name that is less than perfect, it is important that its documentation clearly describe its behavior.

No comments:

Post a Comment

Your comments are welcome!