views:

178

answers:

3

If a thread is interrupted while inside Object.wait() or Thread.join(), it throws an InterruptedException, which resets the thread's interrupted status. I. e., if I have a loop like this inside a Runnable.run():

while (!this._workerThread.isInterrupted()) {
    // do something
    try {
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
    } catch (InterruptedException e) {
        if (!this._isStopping()) {
            this._handleFault(e);
        }
    }
}

the thread will continue to run after calling interrupt(). This means I have to explicitly break out of the loop by checking for my own stop flag in the loop condition, rethrow the exception, or add a break.

Now, this is not exactly a problem, since this behaviour is well documented and doesn't prevent me from doing anything the way I want. However, I don't seem to understand the concept behind it: Why is a thread not considered interrupted anymore once the exception has been thrown? A similar behaviour also occurs if you get the interrupted status with interrupted() instead of isInterrupted(), then, too, the thread will only appear interrupted once.

Am I doing something unusual here? For example, is it more common to catch the InterruptedException outside the loop?

(Even though I'm not exactly a beginner, I tagged this "beginner", because it seems like a very basic question to me, looking at it.)

A: 

That's because an InterruptedException is considered an abnormal event in which someone else tries to stop a thread from outside it.

When you want to really interrupt a thread you just break its loop condition by setting a boolean or something similar. Or you use .wait() and .notify() from inside that thread. But if you are doing wait() externally:

  • an exception is thrown to notify that an external thread tried to interrupt me or to make me wait
  • the thread continues its work because it doesn't take any order from another thread! But the raise of the exception allows you to add special handling and do whatever you want, also effectively stop the thread.
Jack
+2  A: 

The idea is that an interrupt should be handled once. If an explicit InterruptedException did not clear the "interrupt" flag then most catchers for InterruptedException would have to explicitly clear that flag. Conversely, you can "unclear" the flag by self-interruption (Thread.currentThread().interrupt()). Java's designers went for the semantics which would save keystrokes most of the time (i.e. you more often want to clear the flag than keep it set).

Thomas Pornin
I dont disagree with the logic behind what is going on, but they deffinately should have named the method better.
John V.
+1  A: 

Write your code like this and you won't need a flag:

try {
    while (!this._workerThread.isInterrupted()) {
        // do something
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
        // do something else
    }
} catch (InterruptedException e) {
    // ignore ...
}
Stephen C