Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should a method throw InterruptedException, and how should I handle one that does? (blocking method)

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?

like image 887
9628001 Avatar asked Jun 03 '12 06:06

9628001


2 Answers

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.

like image 146
seh Avatar answered Nov 09 '22 20:11

seh


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.

like image 29
Op De Cirkel Avatar answered Nov 09 '22 19:11

Op De Cirkel