Is it OK to ignore InterruptedException if nobody calls interrupt()?
Asked Answered
T

8

53

If I create my own thread (i.e. not a threadpool) and somewhere I call sleep or any other interruptible method, is it ok to ignore the InterruptedException if I know nobody else in the code is doing an interrupt on the thread.

In other words, if the thread is supposed to live as long as the JVM, meaning the thread is not interruptible, is it safe to assume that InterruptedException will never be called and therefore the exception can be swallowed?

Tonality answered 16/2, 2015 at 15:31 Comment(4)
I think the actual question is: Is an InterruptedException ever thrown by the JVM without the code producing it (via Thread.interrupt() etc)Trig
yes. that's another way to put it. But I also wanted to explore the "is there ever a use-case for an uninterruptible thread" aspectTonality
Asking the other way around: "Is my thread safe if I always correctly handle InterruptedExceptions?" - Answer: No. There are un-interruptible (API-)routines, blocking IO for instance, which will render futile every well-meant attempt on InterruptedExceptions. So, ignoring InterruptedExceptions does not usually break anything, i.e. it is "safe". As others have stated, it is rarely "desirable" though.Handiwork
Some containers/runtime wrappers that don't directly "deal" with your code may have a need for interrupting threads. For instance, I was working with the maven exec plugin, and after I made changes where interrupted exceptions were being swallowed, maven would choke when I tried to stop the program with sigterm or ^C.Zelma
A
39

Ignoring a checked exception is never considered to be safe.
It may seem okay for you at the moment, but if any other programmer uses your code/API, they should expect the standard behaviour:

  • Which is, the thread "reacting" to an interrupt call, but with whatever "reaction" the thread's documentation describes.

  • I mean it's up to the thread's developer to both decide and document exactly how a thread handles an interrupt, and Java has not any pre-defined rule, but you should document your thread's "reaction" (with Documentation comments).

  • For example, the InterruptedException is only thrown from blocking methods (like Thread.sleep(...)), but never from normal lines of code (meaning the interrupt is simply ignored by default), which allows developers to choose (and document) thread's reaction, like:

    • Maybe abort, by cancelling task(s) in mid of progress.

    Which takes time for development, if not already supported.

    • Maybe postpone (or soft-ignore), by calling Thread.currentThread().interrupt() in catch-block.

    Which simulates interrupt happening while normal code was running.

    • Maybe crash, by throwing a java.lang.Error (or sub-class), and passing InterruptedException-instance as cause.

    Which unless documented, is least desired or expected.

To explain postpone; An empty catch block is dangerous with InterruptedException, since the JVM removes the interrupted flag, and it should definitely be set again in the catch block, like:

try {
    Thread.sleep(1000);
} catch (InterruptedException ignored) {
    Thread.currentThread().interrupt();
}

In my opinion, this is the minimum catch implementation for InterruptedExceptions. Checking for the isInterrupted flag in a loop doesn't hurt much, either.
It is little overhead compared to your future programmer self's hassle searching a day or two for unexpected thread behaviour as you project may have grown a bit.

If you feel that your code's readability suffers from those catch implementations, you may implement your own safeSleep utility method, which takes care of the Exceptions and sets the flag properly.

On the other hand, InterruptedException is not thrown by the JVM itself in case of a hardware failure, it is a user indicated Exception only. So, if you do not propagate your Threads reference, there won't be any other Threads that are able to call Thread.interrupt() on it. That's it technically. But you shouldn't underestimate the human factor and your programs evolution.
Edit: As ruakh pointed out, there actually is a way to get a Threads reference and thus to schedule an Thread.interrupt() call. That way the developer in heat may not even have to look at the class, that implements your uninterruptible Thread. In my opinion that's even another reason, to implement proper exception handling.
Another thing: If you're not throwing an Exception, logging such an event on a level beyond INFO may be a good choice.

Arethaarethusa answered 16/2, 2015 at 15:39 Comment(7)
What is "the standard behavior?" clean up and shut down?Diazo
@james large in fact, there may be no standard behaviour, but an expected one. that is aborting the current process and finishing gracefully. but as always: documentation is key here.Arethaarethusa
Re: "if you do not propagate your Threads reference there won't be any other Threads, that are able to call Thread.interrupt() on it": Threads aren't like random objects, that you can decide whether or not to propagate. The JDK offer methods for finding all threads. See #1323908 for a few approaches.Nealah
@Nealah Thanks for your comment. I've corrected this in my answer.Arethaarethusa
Regarding the safeSleep method: Instead of implementing your own, you can also use Guava's Uninterruptibles (e.g. Uninterruptibles.sleepUninterruptibly)Excaudate
"On the other hand, InterruptedException is not thrown by the JVM itself": can you support this claim by linking to documentation/specification stating this?Thursday
@EduardWirch I think i got it from a German book by Michael Inden, which I do not have at hand right now. But a quick search brought up this SO-answer, which references the JLS section 17.2.3: Interruption actions occur upon invocation of Thread.interrupt, as well as methods defined to invoke it in turn, such as ThreadGroup.interrupt.Arethaarethusa
K
34

Instead of swallowing it, if you're so sure it will never happen, you can crash instead of ignoring it. For example, throw an Error (or a RuntimeException):

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    throw new Error(e);
}

From the Javadocs for Error:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.

If you think it's worth assuming something will never happen, then if it does happen, that's an "abnormal condition" that, who knows, might just be a "serious problem".

Another way to look at this is, if someone in the future does interrupt your method, is there any chance that they will want it to continue running as if nothing had happened? I would guess no.

Postponing

Another alternative would be postponing, like:

try {
    Thread.sleep(1000);
} catch (InterruptedException ignored) {
    Thread.currentThread().interrupt();
}

// ... do some work ...

if (Thread.currentThread().isInterrupted()) {
    // Handle if possible, and was expected,
    // else, throw new `InterruptedException`.
}

Note that above example-code does not do "if (Thread.interrupted()) {", because that would clear the interrupt flag of the thread (which is a bad pattern).

Kommunarsk answered 16/2, 2015 at 15:46 Comment(5)
I normally use AssertionError for this, but that's mostly just a personal preference.Coker
And, later, when it crashes six months down the line, because you write something that needs to interrupt it, you'll remember why you decided not to silently swallow the error to begin with. Or, you'll have a subtle bug, like data not getting saved to a database, memory leaks, or whatever other resources this thread might be holding.Tharp
UGH. This is ugly, if you are going to rethrow the InterruptedException, just throw the InterruptedException itself. This is especially true for library code. If this is your application code, it really wont make any difference if you rethrown or ignore the exception anyway, since you can guarantee it's not caused in the first place. The other option is to gracefully exit your thread.Transept
@Transept the question was for code written inside a thread. You can't throw an InterruptedException from Runnable.run() unless it's wrapped inside something else. If you mean, "throw the InterruptedException inside some method that you then call", sure, but then what do you do in the thread that calls it?Kommunarsk
Mmm true, once you reach thread level, crashing or gracefully ending your thread are both valid options. Got to agree. Pick what fits best.Transept
S
18

You should never swallow an exception if you think that it should never occur. It’s ok to decide not to add code handling a condition which never occurs but it shouldn’t happen silently.

The minimum you should do is:

catch(InterruptedException ex) {
  throw new AssertionError(ex);
}

This ensures that whenever your assertion that this will never occur is wrong, you will notice. This pattern also applies to other unexpected exceptions, e.g. IOException when you know that the target OutputStream is a ByteArrayOutputStream or the Appendable of a Formatter ought to be a StringBuilder, etc.


By the way, there is an alternative to Thread.sleep not requiring to deal with InterruptedException at all:

LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(timeInMillis));

This method will simply return earlier when the thread has been interrupted and retain the interrupted state of the Thread so it provides already a correct handling for the case that your code is used by someone else who does use interruption (assuming that the caller of your code checks the interrupted state then).

Slifka answered 16/2, 2015 at 15:49 Comment(4)
Also, if you have reason to believe that your code can safely ignore some exception, then you should at least call LOGGER.debug(ex), so that it will be easier to figure out what happened if your belief should somehow turn out to be wrong.Diazo
@jameslarge for me, just printing a log message is still ignoring the exceptionTonality
@Hilikus, I agree. Holger's answer explained why its a bad idea to ignore an exception that you think can never happen. I tacked on my comment to say something about the rare case where you know the exception will happen, and you mean to ignore it.Diazo
+int(PI/3) for LockSupport - you made me learn yet another not-so-common feature of Java today...Magnifico
U
14

The book that I still consider the bible on these matters, Goetz et al. Java Concurrency in Practice says the following important bits in chapter 7 (Pretty much the same material is found in Goetz's developerWorks article, which has the advantage of being free, but the book is a bit more clear on some points.)

Interruption is a cooperative mechanism. One thread cannot force another to stop what it is doing and do something else; when thread A interrupts thread B, A is merely requesting that B stop what it is doing when it gets to a convenient stopping point—if it feels like it.

[...]

Only code that implements a thread’s interruption policy may swallow an interruption request. General-purpose task and library code should never swallow interruption requests.

So, yes, you can "swallow" InterruptedException under the circumstances you outlined.

Also an important point in the book:

Because each thread has its own interruption policy, you should not interrupt a thread unless you know what interruption means to that thread.

So you can choose your own policy like "crashing" with a RuntimeException, AssertionError, just logging it as a warning, or ignoring interruption altogether as long as you document this issue for whoever else might need to know. What is best depends on what your thread is really doing and you haven't provided any details on that. For example, if it's running on a rocket [say doing attitude control], you do not want to crash the JVM/rocket just because a fellow programmer [who might not even work for the same company as you, e.g. he wrote some library you call] forgot about a certain contract somewhere in his code and dumps a safely ignorable exception on yours: "The exception which occurred was not due to random failure but a design error."

Unmannerly answered 17/2, 2015 at 1:47 Comment(0)
L
8

It should not be ignored. It should either be thrown back to the caller, or you should reassert the thread's interrupted status, because staid status gets cleared when the InterruptedException was thrown:

} catch (InterruptedException e) {
    // Restores the interrupted flag status.
    Thread.currentThread().interrupt();
}

Unless you promptly exit the thread after the catch.

Here's an article about dealing with InterruptedExceptions.

Example

The InterruptedException is only thrown from blocking methods (like Thread.sleep(...)), but never from normal lines of code, and it's up to the programmer to decide exactly how a thread responds to an interrupt.

For example, there was a project which just did document it, like:

public class MyTask {

// ...

/**
 * Waits for result to be use ready.
 * <br>
 * <br>
 * <b>Warning:</b> instead of throwing {@link InterruptedException},
 * returns {@code null}, and if that is undesired, do something like:
 *
 * <pre>{@code
 * MyResult result = myTask.await(...);
 * if (Thread.currentThread().isInterrupted()) {
 *     throw new InterruptedException();
 * }
 * }</pre>
 *
 * @param timeout Duration to wait at most.
 * @param unit    Type of duration.
 */
public MyResult await(long timeout, TimeUnit unit) {
    try {
        return /* ... */;
    } catch (InterruptedException e) {
        // Restores the interrupted flag status.
        Thread.currentThread().interrupt();
    }
    return null;
}

}

Note that above doc-block's code does not do if (Thread.interrupted()) {, because that would clear the interrupt flag on the thread (which is a bad pattern).

Layby answered 16/2, 2015 at 15:38 Comment(1)
If you just re-throw the exception, wouldn't that have the same effect as killing the thread with the deprecated Thread.stop() method? Who will catch the exception?Cannonball
C
7

If your Projekt grows and gets more complex, it's getting harder to say that definitely no one would call the interrupt method. If someone would call this method some day and an InterruptedException occurs it's getting really hard to debug this if you're not at least logging it somewhere.

Cynical answered 16/2, 2015 at 15:37 Comment(0)
P
2

if the thread is supposed to live as long as the JVM, meaning the thread is not interruptible, is it safe to assume that InterruptedException will never be thrown and therefore the exception can be swallowed?

I understand your pain, the proliferation of boilerplate try-catch blocks with no business value hurts the code.

If the code where you intend to swallow the exception is entirely under your control, and if it is just client code (it will never be reused in context other than your own), then it is safe to swallow the exception. Note that there are a lot of ifs there.

If you happen to work with Java 8, you have another option, described here: wrap your code inside an uncheckCall(() -> { ... }) block. This lets the code block throw the InterruptedException without declaring it. As explained in the linked answer, this should be handled with extreme care, but it has the potential of making your code quite clean.

Potboiler answered 16/2, 2015 at 15:56 Comment(0)
M
1

I think, ignoring InterruptedException is safe or not, depends upon what you are doing in that thread. If there is any scenario when an unwanted interrupt to your thread can leave System or any resource in unwanted state (dirty, locked, not released which can cause leaking resource) then its your responsibility to handle the InterruptedException and you should not ignore it. It's up to you whether you want your to make your thread Interruptible or not.

In other words Interrupt mechanism is mainly used for implementing the cancellation policies and task clean up. Is you don't have anything to clean in task or you dont have any specific task cancellation policies, ignoring IntrruptedException may not sound politically correct but is OK.

Mauve answered 16/2, 2015 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.