[concurrency-interest] JCiP Memoizer

David Holmes dcholmes at optusnet.com.au
Wed Oct 18 06:28:47 EDT 2006


Alex,

I have to concur with Tim. The intent was that interruption during ft.run()
implied cancellation and so there was a need to do clean-up of the cache
entry. But there is nothing to convert the interruption to a cancel()
request and so all that happens in the current case is that everyone who
calls f.get() will get ExecutionException with a cause of
InterruptedException.

Assuming the general case and there was a means to cancel() the FutureTask
then I would be tempted to rewrite the code as follows:

    try {
       return f.get();
    }
    catch (CancellationException e) {
       cache.remove(arg, f);
    }
    catch (ExecutionException e) {
       Throwable t = e.getCause();
       if (t instanceof InterruptedException) // ft.run was 'cancelled'
          cache.remove(arg,f);
       throw launderThrowable(t);
    }

But this doesn't quite work right as it causes an InterruptionException in
both the thread that actually got the interrupt (the one that ran ft.run() )
and any thread that happened to be blocked on f.get() at the time. (Later
threads will re-compute due to the cache removal). What we want to be able
to do is determine if the current thread is the one that executed ft.run()
and only in that case throw the InterruptException. One way to do that would
be to declare ft at the top of the while loop and check for ft != null eg:

    try {
       return f.get();
    }
    catch (CancellationException e) {
       cache.remove(arg, f);
    }
    catch (ExecutionException e) {
       Throwable t = e.getCause();
       if (t instanceof InterruptedException) { // ft.run was 'cancelled'
          cache.remove(arg,f);
          if (ft != null)  // we did ft.run() so we were interrupted
             throw (InterruptedException) t;
          // else retry
       else {
          throw launderThrowable(t);
       }
    }


Note that if compute() doesn't convert an interrupt to InterruptedException
then we presume it did not actually abort the computation. Hence finding the
interrupt bit set after ft.run() is not an indication of cancellation.

And as per the text if you might be able to recompute then any
ExecutionException might be used to just remove the cache entry, and only
throw if the current thread was the one that invoked ft.run().

Cheers,
David Holmes

> -----Original Message-----
> From: concurrency-interest-bounces at cs.oswego.edu
> [mailto:concurrency-interest-bounces at cs.oswego.edu]On Behalf Of
> Alexandru Popescu
> Sent: Wednesday, 18 October 2006 6:06 PM
> To: concurrency-interest
> Subject: Re: [concurrency-interest] JCiP Memoizer
>
>
> On 10/18/06, Tim Peierls <tim at peierls.net> wrote:
> > It's only 1am here, but it looks funny to me, too. I remember that the
> > intent was that a thread interrupted in the middle of a long computation
> > should not leave the incomplete computation lying around in the
> cache. So
> > any thread that detects a cancellation removes the task from
> the cache and
> > tries again.
> >
> > But an interruption during ft.run() will not be seen as a
> cancellation of
> > the FutureTask, so this doesn't work. The fix would probably involve
> > checking for interruption after the call to ft.run().
> >
> >  I just read Joe's response, but I don't see how a Memoizer-created
> > FutureTask, encapsulated as it is, could ever be cancelled.
> (Also, I don't
> > think cache.remove(arg, f) ensures that only the task creator
> removes the
> > task; it just ensures that the only the failed task is removed.)
> >
>
> (a bit later: early in the morning): Things are starting to become
> more clear. I don't think there is any way a FutureTask can be
> cancelled (cause I don't see it published). Also, I am not sure how
> can you reach a CancellationException (for the same reasons).
>
> Another question related to the same code would be: what if the
> compute method must not perpetuate the InterruptedException? Wouldn't
> this qualify for the cache.remove call? (because as far as I get it,
> if the expensive computation resulted in an InterruptedException, then
> you will never get the change to compute the real value.
>
> Sorry if I ask wrong questions, but the code looks pretty interesting
> (and I am doing an attempt to further detail it to my collegues, that
> may need to use something similar).
>
> ./alex
> --
> .w( the_mindstorm )p.
>
>
>
> > --tim
> >
> >
> >
> > On 10/18/06, Joe Bowbeer < joe.bowbeer at gmail.com> wrote:
> > > On 10/17/06, Alexandru Popescu <
> > the.mindstorm.mailinglist at gmail.com> wrote:
> > > >
> > > > I would start by saying that till now Chapter 5 is my
> favorite so far
> > > > :">. Still, I have a small problem (indeed it is 5am) understanding
> > > > the final version of Memoizer (page 108), or at least one line from
> > > > it:
> > > >
> > > > public V compute(final A arg) throws InterruptedException {
> > > >    while(true) {
> > > >             // code
> > > >     }
> > > > }
> > > >
> > >
> > > It's because of this line further down:
> > >
> > >             } catch (CancellationException e) {
> > >                 cache.remove(arg, f);
> > >
> > > from http://jcip.net/listings/Memoizer.java
> > >
> > > Here's a partial explanation:
> > >
> > > The memoizing compute method is trying to reflect the exception from
> > > the wrapped method back to the caller, but it also has to handle the
> > > case where the task may have been cancelled (somehow).
> > >
> > > In this case, the compute method removes its task from the cache (iff
> > > it created the task) and tries again.
> > >
> > > --Joe
> > > _______________________________________________
> > > Concurrency-interest mailing list
> > > Concurrency-interest at altair.cs.oswego.edu
> > >
> > http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
> > >
> >
> >
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at altair.cs.oswego.edu
> http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest



More information about the Concurrency-interest mailing list