SSerguey Asael Shinder
Java coding notes: the JVM, and writing software that lasts

Serguey Asael Shinder: Catching InterruptedException clears the flag, so an empty catch loses the interrupt

· by Serguey Asael Shinder / Serguey Shinder

This is one of the most common blocks in Java code:

try {
    Thread.sleep(1_000);
} catch (InterruptedException e) {
    // ignore
}

It looks like it only skips a pause. It actually throws away a request to stop.

What the exception means. An interrupt is how one thread asks another to stop what it is doing. Blocking methods such as Thread.sleep respond by throwing InterruptedException. The important part is in the javadoc of Thread.sleep(long)), under the exception: "The interrupted status of the current thread is cleared when this exception is thrown." The same sentence appears on join and the other blocking methods of Thread.

So after the catch block runs, the thread looks as if it had never been interrupted. The request now exists only inside the exception object — and an empty catch drops it.

Serguey Asael Shinder: Catching InterruptedException clears the flag, so an empty catch loses the interrupt
Catching InterruptedException clears the flag, so an empty catch loses the interrupt — Serguey Asael Shinder

Why that breaks things above you. The code that calls yours often relies on the flag. A worker loop written as while (!Thread.currentThread().isInterrupted()) { ... } keeps going, because the status was cleared one level down. Any code that stops threads by interrupting them and then waits for them to finish ends up waiting longer than it should. Nothing fails loudly; the program is just slower to stop than it should be, or does not stop at all.

Checking the flag can clear it too. The static Thread.interrupted()) also clears the status — its javadoc says that two calls in a row would return true and then false. The instance method isInterrupted() leaves it unchanged. Using the static one "just to check" has the same effect as swallowing the exception.

What to write instead. Pick one of two honest responses:

} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    return;
}

Then stop the work: return, or exit the loop. Restoring the flag and carrying on as normal only moves the problem to the next blocking call.

The rule of thumb: an InterruptedException is a message addressed to the whole call stack, not just to the method that happened to be sleeping. A catch that neither rethrows nor restores the flag reads that message and throws it away.