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

David M. Lloyd david.lloyd at redhat.com
Thu Apr 8 20:52:06 EDT 2010


Since you only have uninterruptible variants, maybe you could drop the 
"Uninterruptibly"?  That's a horrible word to type ;)

On 04/08/2010 07:32 PM, Jim Newsham wrote:
>
> Regarding decision A. We have a collection of static
> XXXUninterruptibly() methods in a single utility class. This is like
> your approach #1, except they are all in the same class (ours is called
> ThreadUtils and has some other thread-related methods, but I've
> sometimes considered breaking them out into a separate class which
> contained only XXXUninterruptibly()... maybe
> UninterruptibleUtils.get(Future) or Uninterruptibly.get(Future)?). We
> didn't really consider (or have a need for) the wrapper approach -- it's
> really the invoker who decides whether to mask interruption.
>
> Regarding decision B. In our case, the code for each method is repeated,
> but it's really not much code at all so I have no issue with it.
>
> Jim
>
> On 4/8/2010 6:46 AM, Chris Povirk wrote:
>> My goal is a family of operations like these:
>>
>> // Neither of these throws InterruptedException.
>> V result = Futures.getUninterruptibly(future);
>> CountDownLatches.awaitUninterruptibly(latch);
>>
>> These methods would retry the operation until it completes without
>> interruption and then restore the interrupt. (Another option is to
>> wrap the InterruptedException in a custom InterruptedRuntimeException
>> class; I'd be happy to hear people's opinions on this, as well.)
>>
>> Google has implementations of some of these operations, and we're
>> planning to expand our coverage and release them in our open-source
>> Guava project. However, we're uncertain about a few issues.
>>
>> Below I've listed the two main decisions we need to make along with a
>> number of pros and cons for each of their options.
>>
>>
>> Decision A: The interface to these uninterruptible methods could take
>> one of three forms:
>> 1. Static Futures.getUninterruptibly methods.
>> 2. A static uninterruptibleFuture method that returns an
>> UninterruptibleFuture, which adds getUninterruptibly methods to
>> Future.
>> 3. A static uninterruptibleFuture method that returns an
>> UninterruptibleFuture, which overrides Future's get methods to no
>> longer throw InterruptedException.
>>
>> (1) requires the fewest method declarations.
>>
>> The method declarations from (1) are likely to be jumbled together
>> with unrelated declarations. A person who sees
>> BlockingQueues.putUninterruptibly, takeUninterruptibly,
>> offerUninterruptibly, and pollUninterruptibly may get the impression
>> that the BlockingQueues contains only InterruptedException-removing
>> methods, when perhaps it contains methods like takeMultiple(Queue<E>,
>> int). Plus, subclassing is awkward: does BlockingDeques provide a
>> static putUninterruptibly method, too? (An alternative is to put
>> methods for all interfaces in a single Uninterruptibles class.)
>>
>> (1) is the best solution for classes with final methods (notably
>> Thread.join). Even (2) suffers from this problem:
>> joinUninterruptibly() would join the delegate thread, as desired, but
>> join() (which we can't override) would join the unstarted wrapper
>> thread. This is confusing. Luckily, Thread.join and other primitives
>> are used less frequently than they used to be, especially among the
>> kind of people that I hope will use the uninterruptible wrappers.
>> (Related: Developers who want to make their methods final can define
>> interfaces so that we don't need to override the class's methods.)
>>
>> Declaring a variable or field to be an UninterruptibleFuture (possible
>> in (2) or (3)) can express our intention to use it that way to readers
>> and make the uninterruptible methods available in IDE autocompletion.
>>
>> Methods can declare a return type of UninterruptibleFuture, making the
>> uninterruptible operations more convenient and bringing them to the
>> attention of more users.
>>
>> (3) hides the original, interruptible methods. This is especially a
>> problem if a method has returned an UninterruptibleFuture to the user
>> for "convenience," as proposed above.
>>
>> (2) is most consistent with the JDK's existing uninterruptible methods.
>>
>> In principle, a Future implementation could implement
>> UninterruptibleFuture and some other Future subinterface (e.g., one
>> whose get methods do not throw ExecutionException). In practice, this
>> seems unlikely.
>>
>> "UninterruptibleFuture" is a poor name. The name may suggest to some
>> that a *task* whose value the Future awaits may not be interrupted
>> through Future.cancel. But "Uninterruptible" refers only to the get
>> methods; it's more like "UninterruptiblyGettableFuture," which is an
>> ugly name.
>>
>> "UninterruptibleFuture" is a particularly poor name in the case of
>> (2), since its get methods would still be interruptible. (This is
>> another problem that "UninterruptiblyGettableFuture" could solve.)
>>
>>
>> Decision B: There are two ways to handle the retry boilerplate:
>> 1. Repeat it everywhere it's needed.
>> 2. Delegate to a performUninterruptibly method that takes an
>> InterruptibleOperation parameter.
>> (<http://cs.oswego.edu/pipermail/concurrency-interest/2007-March/003775.html>)
>>
>>
>> (A colleague proposed a reflection-based alternative, but we found it
>> to have two problems: First, CountDownLatch isn't an interface, so we
>> can't extend it to create an UninterruptibleCountDownLatch interface
>> to pass to Proxy. Second, we can't handle timeouts without either
>> annotating the long+TimeUnit parameters or assuming that there's a
>> convention for them.)
>>
>> (1) has the usual advantages and disadvantages of copy-and-paste
>> programming.
>>
>> If there's a significant performance difference, (1) is surely the
>> winner.
>>
>> (2) requires three variants of InterruptibleOperation: one for
>> operations without timeout, one for operations that time out by
>> returning a sentinel value, and one for operations that time out by
>> throwing TimeoutException. (We might be able to combine the last two
>> with suitable generics, but my claim of "three variants" already
>> presumes some awkward parameterization to handle exceptions.)
>>
>>
>> I'm currently leaning toward 2-1
>> (UninterruptibleFuture.getUninterruptibly, repeat the boilerplate),
>> but some smart people disagree. Opinions?
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> Concurrency-interest at cs.oswego.edu
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-- 
- DML ☍


More information about the Concurrency-interest mailing list