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

Joe Bowbeer joe.bowbeer at gmail.com
Fri Apr 9 02:33:38 EDT 2010


Chris,

My suggestion to thrown an IllegalStateException was a vote for
"failing-fast" if the no-interrupt precondition was violated. It was not
meant to fool the programmers into thinking that their operation would
always complete.

Programming "responsively" with respect to interrupts is hard to do and
tedious to maintain, and I am concerned that programmers will be fooled into
thinking that some API is responsive to interrupts -- because it preserves
the interrupt flag and may eventually throw an IE -- when in practice the
code can wait forever before it finally responds to the interrupt.

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

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

Joe


On Thu, Apr 8, 2010 at 8:36 PM, Chris Povirk wrote:

> Joe,
>
> Thanks for the response.
>
> You're right that the subject line I chose has artificially narrowed
> the discussion to the "never interrupted" case.  In the end, the
> question I'm interested in is "What should a Future.get that doesn't
> throw InterruptedException look like?"  It's a truism that a
> loop-and-retry implementation is the right implementation when you
> want loop-and-retry, as you point out, so I didn't want to dwell on
> this point.  But the result was an e-mail that focused too much on the
> "never interrupted" case.  I believe that there is value in supporting
> both use cases, and, as I'll now argue, I believe that loop-and-retry
> can do that.
>
> We agree about the unique advantage of loop-and-retry.  I disagree,
> however, that that strategy is more specialized than the
> RuntimeException strategy.  I see loop-and-retry as the better
> approach for calls that "will never be interrupted."
>
> The reason is the same as the reason that I put scare quotes around
> "will never be interrupted."  I think we can agree that, if an
> operation truly is never interrupted, any reaction to
> InterruptedException is equally effective -- retry, wrap, ignore,
> System.exit, Runtime.exec("rm -rf /")....  The question is what to do
> when the "impossible" interrupt occurs.  I believe (based on evidence
> from Google and non-Google code) that we as programmers are much too
> quick to assume that an interrupt is impossible.
> (executor.submit(task).cancel(true) would catch a lot of our libraries
> by surprise.)
>
> You've pointed out the responsiveness advantage of handling interrupts
> by throwing a RuntimeException.  This is an advantage, but I don't see
> it as a large one.  Uninterruptible tasks already exist --
> uninterruptible IO, heavy math computations, or callers of
> Semaphore.acquireUninterruptibly, for example.  A task that does not
> exit when interrupted can be a problem, but it's a problem that many
> systems must already cope with.
>
> More important is the disadvantage of throwing a RuntimeException: it
> encourages the programmer to believe that the operation will always
> complete even though the implementation makes no such guarantee.  If
> the programmer believed that the exception were possible, he would
> have caught or propagated the original InterruptedException; there
> would be no need for an uninterruptible wrapper.  We've made it easier
> for him to believe that queue.putUninterruptibly(task) "can't fail,"
> but if it does, his program drops a task on the floor.
>
> Additionally, I believe there's less value in a library implementation
> of the RuntimeException-throwing variant because it's comparatively
> easy for the programmer to write himself (especially if the
> InterruptedRuntimeException constructor restores the interrupt for
> him):
>
> try {
>  ... perform any number of interruptible operations ...
> } catch (InterruptedException e) {
>  throw new InterruptedRuntimeException(e);
> }
>
> As opposed to:
>
> ... maybe declare a field outside the finally block ...
> boolean interrupted = false;
> try {
>  long timeoutNanos = timeoutUnit.toNanos(timeoutDuration);
>  long end = System.nanoTime() + timeoutNanos;
>  while (true) {
>    try {
>      ... perform one number of interruptible operations ...
>    } catch (InterruptedException e) {
>      timeoutNanos = end - System.nanoTime();
>      interrupted = true;
>    }
>  }
> } finally {
>  if (interrupted) {
>    Thread.currentThread().interrupt();
>  }
> }
> ... repeat for each other interruptible operation...
>
>
> Jim: Thanks, we've considered throwing everything into an
> Uninterruptibles class.  This solves a couple of the problems that
> arise from splitting the methods across classes named Futures,
> BlockingQueues, etc.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20100408/37aac841/attachment.html>


More information about the Concurrency-interest mailing list