InterruptedException
is a confusing beast - it shows up in seemingly innocuous methods like Thread.sleep()
, but handling it incorrectly leads to hard-to-manage code that behaves poorly in concurrent environments.
At its most basic, if an InterruptedException
is caught it means someone, somewhere, called Thread.interrupt()
on the thread your code is currently running in. You might be inclined to say "It's my code! I'll never interrupt it!" and therefore do something like this:
// Bad. Don't do this.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// disregard
}
But this is exactly the wrong way to handle an "impossible" event occurring. If you know your application will never encounter an InterruptedException
you should treat such an event as a serious violation of your program's assumptions and exit as quickly as possible.
The proper way to handle an "impossible" interrupt is like so:
// When nothing will interrupt your code
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new AssertionError(e);
}
This does two things; it first restores the interrupt status of the thread (as if the InterruptedException
had not been thrown in the first place), and then it throws an AssertionError
indicating the basic invariants of your application have been violated. If you know for certain that you'll never interrupt the thread this code runs in this is safe since the catch
block should never be reached.
Using Guava's Uninterruptibles
class helps simplify this pattern; calling Uninterruptibles.sleepUninterruptibly()
disregards the interrupted state of a thread until the sleep duration has expired (at which point it's restored for later calls to inspect and throw their own InterruptedException
). If you know you'll never interrupt such code this safely avoids needing to wrap your sleep calls in a try-catch block.
More often, however, you cannot guarantee that your thread will never be interrupted. In particular if you're writing code that will be executed by an Executor
or some other thread-management it's critical that your code responds promptly to interrupts, otherwise your application will stall or even deadlock.
In such cases the best thing to do is generally to allow the InterruptedException
to propagate up the call stack, adding a throws InterruptedException
to each method in turn. This may seem kludgy but it's actually a desirable property - your method's signatures now indicates to callers that it will respond promptly to interrupts.
// Let the caller determine how to handle the interrupt if you're unsure
public void myLongRunningMethod() throws InterruptedException {
...
}
In limited cases (e.g. while overriding a method that doesn't throw
any checked exceptions) you can reset the interrupted status without raising an exception, expecting whatever code is executed next to handle the interrupt. This delays handling the interruption but doesn't suppress it entirely.
// Suppresses the exception but resets the interrupted state letting later code
// detect the interrupt and handle it properly.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return ...; // your expectations are still broken at this point - try not to do more work.
}