[concurrency-interest] InterruptedException-free wrappers for calls that "will never be interrupted"

Chris Povirk cpovirk at google.com
Fri Apr 9 11:52:51 EDT 2010


I understand that fail-fast behavior is a worthy goal.  My bigger
concern is the other effect of the change, which is to convert a
checked exception to an unchecked exception without changing the
circumstances under which the exception occurs.  My question, then, is
what you expect programmers to do with the IllegalStateException.
Either they're expected to catch it (in which case I think they're
better served by the original checked exception[*]), or they're
expected to ignore it (in which case they're vulnerable to the "this
will never happen"mistake).  We may just disagree over the merits of
code that fails quickly but at a spot the programmer doesn't expect
the code to fail.

Alternatively, we may disagree over the likelihood that the programmer
will understand that, despite the lack of a checked exception, the
interruptible operation may fail.  My experience is that, even in the
case of the checked InterruptedException, programmers make the
unjustified assumption that it will never occur:

Maybe some of these are justified, but much of the code seems to be in
library methods that can't possibly know they won't be interrupted.

This brings me to my secret goal: The next time we announce the latest
batch of new Java libraries, I want to be able to say: "Annoyed by
InterruptedException?  Reade Goetz's 'Dealing with
InterruptedException,' and consider our new family of
InterruptedException-free methods in the Uninterruptibles class (e.g.,
Uninterruptibles.get(Future)) to make your operations uncancellable."
In an ideal world, everyone will read the article and apply it.  In
the real world, we will (I hope) see many more Uninterruptibles.get
calls in place of the catch-and-swallow idiom I see too often now.
It's partially an education problem, but I can understand if people
who don't expect to use task cancellation don't want to read 2400
words about InterruptedExcetion just to implement it.  (And the
implementation can be, as you say, tedious.)  One role of
Uninterruptibles.get is to provide an easier solution for them.  As a
bonus, the Uninterruptibles class should provide a good place to link
to Goetz's article so that anyone interested enough to investigate
Uninterruptibles.get can learn more.

> I also question whether reasserting the interrupt is adequate.  If every
> method reasserts the interrupt, when is the interrupt actually handled?

I admit that it's possible that it will be handled nowhere.  If forced
to choose between "abort unexpectedly and continue processing with n
threads" or "resume and continue processing with n-1 threads for a
time," I'll choose the latter.  "Abort in a controlled manner and
continue processing with n threads" is the ideal, but by accepting any
InterruptedException-free method, we've in effect abandoned the ideal.

That aside, it's possible that even if one library I call loops and
restores the interrupt, the next library I call will use it as a
cancellation signal, so it will still take effect, just not as quickly
as it could have.

> If the intent is to wait until Future.get completes, even if interrupted,
> then why not throw IE upon completion?

Most callers of Future.get are interested in the return value, which
they won't receive if the method throws.  Maybe that's OK if the
caller was going to do a lot more work with that value before
returning (so the IE prevented the operation from continuing), but if
"return Uninterruptibles.get(future)" is the last significant thing
the caller does, then throwing IE serves only to cancel a job after
it's done but before it's returned its result.  My intent isn't so
much to wait for completion as it is to ensure that, if the operation
*looks* like it will always complete (i.e., no checked exception),
then it will.  The choices in my mind are "Throw IE immediately when
interrupted" (to get the full benefit of interruption) or "Don't throw
IE at all."  Future isn't the only example here; consider the expected
blockingQueue.put(task) failure I mentioned earlier.

Additionally, not throwing IE is the more flexible approach, as it's
simple to manually throw one if desired (especially in comparison to
the code to do the reverse):

V result = Uninterruptibles.get(future);
// Could write a utility method to reduce this to one line:
if (Thread.interrupted()) {
  throw new InterruptedException();

[*] The original programmer of a piece of code seems to be good enough
at ignoring a checked exception.  Even if we can convince him not to
ignore an unchecked exception (probably through a scary-sounding
method name), later programmers may not go back to read the
documentation.  This is especially true if they don't touch the method
that calls getNeverInterrupted itself but instead touch a method that
calls it.  Who would guess that issueQuery() would throw
IllegalStateException if interrupted?  (Or do we expect people to call
it "issueQueryNeverInterrupted?")

Doug: Thanks.  Still digesting all of that.

More information about the Concurrency-interest mailing list