15

If a method must be a blocking method, am I right in thinking that if I leave out throws InterruptedException, I have made a mistake?

In a nutshell:

  • A blocking method should include throws InterruptedException otherwise is a normal method.
  • A blocking method can compromise responsiveness because it can be hard to predict when it will complete that's why it needs throws InterruptedException.

Is that correct?

seh
  • 14,999
  • 2
  • 48
  • 58
9628001
  • 509
  • 1
  • 4
  • 11

3 Answers3

30

No, I don't find your summary to be correct. Usually, if you're writing a method that calls on others that throw InterruptedException, then your method should also advertise throwing InterruptedException—unless you have a good plan for what to do when the methods on which yours relies signal interruption.

The cases where you'll be able to absorb such interruption are rare. Perhaps you're computing an iterative solution, where the precision increases with time, but, upon your calling thread being interrupted, you decide that the solution you've reached in the allotted time is good enough, and is still correct enough to return. In other words, that solution is still within your method's range.

Imagine:

private double improveUpon(double start) throws InterruptedException {
  // ...
}


public double compute() {
  double result = 0.0;
  try {
    do {
      result = improveUpon(result);
    } while (couldBeImproved(result));
  } catch (InterruptedException ex) {
    Thread.currentThread().interrupt();
  }
  return result;
}

Alternately, if you merely want to respect an interruption request, you can do so without InterruptedException being involved:

private double improveUpon(double start) {
  // ...
}


public double compute() {
  final Thread current = Thread.currentThread();
  double result = 0.0;
  do {
    result = improveUpon(result);
  } while (couldBeImproved(result) &&
           !current.isInterrupted());
  return result;
}

For yet another variation, consider the case where your method must either complete all its work or indicate to the caller that it could not complete it, and it takes a while to get there, but you want to respect thread interruption. Something like this will suffice:

private double improveUpon(double start) {
  // ...
}


public double compute() throws InterruptedException {
  final Thread current = Thread.currentThread();
  double result = 0.0;
  do {
    if (current.interrupted())
      throw new InterruptedException();
    result = improveUpon(result);
  } while (!isAdequate(result));
  return result;
}

Note there that we called on Thread#interrupted(), which has the side effect of clearing the thread's interruption status if it had been set. If that method returns true, we as the caller have accepted the responsibility to hold and communicate that interruption status. In this case, since we do not assume that we created the calling thread and we don't have enough scope visible here to know what its interruption policy is, we communicated the interruption status we observed and adopted by throwing InterruptedException.

Labeling a method as "blocking" is always a matter of degree; every method blocks its caller for some amount of time. The distinction you may be looking for is whether the method blocks waiting on some external input, such as a user pressing a key or a message arriving over a network. In those cases, advertising that you throw InterruptedException indicates to your caller that your method is safe for use by callers from threads that must control their latency. You're saying, "This may take a while to complete, but it will take no longer than you're willing to wait." You're saying, "I'll run until you tell me not to." That's different from, say, java.io.InputStream#read(), which threatens to block until one of three conditions occur, none of which is the caller's thread being interrupted.

In most cases, your decision comes down to answering the following questions:

  • To satisfy my method's requirements, do I need to call on any methods that throw InterruptedException?
  • If so, is the work I've done up to that point of any use to my caller?
  • If not, I too should throw InterruptedException.
  • If nothing I call throws InterruptedException, should I respect my calling thread`s interruption status?
  • If so, is any work I've done up to the point at which I detect that I've been interrupted of any use to my caller?
  • If not, I should throw InterruptedException.

The situations in which one will detect the current thread's interruption and swallow it are usually confined to those where you, the author, created the thread in question, and you have committed to exiting the thread's run() method once the thread gets interrupted. That's the notion of "cooperative cancellation," wherein you observe the request for your thread to stop running, and you decide to abide by that request by finishing your work as quickly as possible and letting the thread's call stack unwind. Again, though, unless you're the author of the thread's run() method, you swallowing the thread's interruption status is likely harming the intended behavior of your callers and of the other methods upon which they call.

I suggest that you study the topic of a thread's interruption status, and get comfortable with the methods Thread#isInterrupted(), Thread#interrupted(), and Thread#interrupt(). Once you understand those, and see that an InterruptedException being in flight is an alternate representation of Thread#isInterrupted() having returned true, or a courteous translation of Thread#interrupted() having returned true, this should all start making more sense.

If you need more examples to study, please say so and I can add recommendations here.

seh
  • 14,999
  • 2
  • 48
  • 58
  • Your example is too trivial to explore the subtleties of multi-threaded code. Imagine code that was waiting for a resource to become available - many threads could be waiting, and all may be woken, but only one gets in first so the others must continue waiting. You example doesn't show this - it simply stops on interrupt, which is acceptable only in the most trivial of examples. Also, you should read up on "spurious wakeups" - you have not catered for these, because you have no wait condition. Your comment that "all methods block" is naive and wrong: "blocking" means "may block forever" – Bohemian Jun 03 '12 at 13:41
  • 2
    I understand spurious wake-ups perfectly well, and they are not germane to this discussion. Where do you see any calls in my examples that are vulnerable to spurious wake-ups? – seh Jun 03 '12 at 13:48
  • 2
    @Bohemian: spurious wakeups have nothing to do with InterruptedExceptions. A spurious wakeup happens when `wait()` returns without any `notify` call. InterruptedException happens when a thread blocked on an interruptible blocking call has been interrupted. – JB Nizet Jun 03 '12 at 13:53
  • 2
    A great +1. Your final list of questions to ask yourself is perfect. – JB Nizet Jun 03 '12 at 13:58
5

InterruptedException is (usually) thrown when thread blocked on a method gets interrupt() called on it.

The point of it is to unblock (for some reason) a thread that is blocked. Example of reason is application shutdown. So, when you shutdown your application, if you have threads waiting on let say sleep() or wait() , if you do not tell them that you are shutting down they will continue to wait(). If those threads are not daemon threads, then your application won't shutdown.

So, when thread gets interrupted during sleep(), you have to check the conditions and handle the situation. In case of shutdown, you have to check your shutdown flag and eventually do the clean-up work and let the thread go.

Threads can be interrupted because of some other reasons, but the point is the same. If you have multi-threaded application you have to establish protocol for your threads so that they know when there is some special condition how to handle it. In case the thread is waiting/sleeping, you have to wake it up to handle the situation. The clinets of your library or framework do not know anytrhing about your protocol, so they don't know how to handle InterruptedException because of that the recomendation is to handle it in your library/framework code.

Op De Cirkel
  • 28,647
  • 6
  • 40
  • 53
-1

If your method blocks, it should catch and handle InterruptedException, and prefer not to re-throw it.

Also, the method may block in several places - each place should catch and handle InterruptedException in a way appropriate for the place where it could be thrown.

The bible on the subject of multi-threaded code is Java Concurrency in Practice. I highly recommend you read it.

Edited:

When designing your concurrent code, realise that:

  • According to the JVM spec, InterruptedException may be thrown randomly by the JVM for no reason at all (known as a "spurious wakeups")
  • Many threads may be waiting on the same condition, all may be woken (eg by notifyAll()), but only one may advance when interrupted

so whenever a thread is woken, it should check the state of the wait condition it is waiting for and potentially go back to waiting.

Thus, properly written concurrent code should catch InterruptedException. You can chose to re-throw it or throw your own application-specific exception. "Application code" methods should prefer to throw "application" exceptions, however if your waiting code may find itself in a state where it's not possible to figure out "what went wrong", then your only option is to throw InterruptedException.

Community
  • 1
  • 1
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • This advice sounds backwards to me. This method you propose that's catching and swallowing `InterruptedException` needs some way to indicate to its caller that it was not able to complete the intended operation, because it got interrupted before it could do so. And how do you propose that the method indicate that condition to its caller? – seh Jun 03 '12 at 12:52
  • I think it depends on what layer in your application would you be able to handle the interruption properly; "properly" is subjective here and it depends on a lot of factors specific to the system. – Zaki Jun 03 '12 at 13:00
  • @Zaki It doesn't "depend on which layer handles the exception". That choice is irrelevant to API design: The method that's waiting doesn't know anything about its caller. The choice of which layer catches the exception is made by the caller, not the method being called. You may throw an exception from the method, but don't throw a low-level thread exception. Whatever you throw, decide which layer handles it as you like. See edited answer for more explanation – Bohemian Jun 03 '12 at 13:31
  • 5
    Nearly all blocking methods in the JDK throw InterruptedException. And you're confusing spurious wakeups with "spurious exception" (which doesn't exist, AFAIK). What the bible says is precisely that the best thing to do when an InterruptedException happens and you don't know how to handle is to propagate it. Re-read section 7.1.3 of JCIP. – JB Nizet Jun 03 '12 at 13:35
  • @JBNizet Good point. I've edited my answer to incorporate it (I changed "never throw" to "prefer not to throw") – Bohemian Jun 03 '12 at 13:54
  • 4
    I still think your answer is completely wrong. InterruptedException is the best exception to throw to signal that the work couldn't be done due to the thread being interrupted. And spurious interruptions don't exist. InterruptedException may **NOT** be thrown randomly by the JVM. – JB Nizet Jun 03 '12 at 14:01