[concurrency-interest] ScheduledThreadPoolExecutor woes

Tim Peierls tim at peierls.net
Sat Jan 20 11:39:41 EST 2007


Last spring Josh Bloch proposed an interface and some standard
implementations to capture something like what Bela described.

public interface RetryPolicy {
    boolean isFailureRecoverable(Exception e);
    long nextDelay(long startTime, int retries);
}

The implementations included exponential backoff, truncated exponential
backoff, and fixed delay.

There was also a factory method for an ExecutorService wrapper to wrap
Runnables and Callables with the machinery needed to implement a given
RetryPolicy.

The idea is that a task signals that it may be retried by throwing an
exception e for which RetryPolicy.isFailureRecoverable(e) is true, and the
nextDelay method decides, based on the start time of the initial attempt and
the number of retries that have occurred, how long to wait before trying
again. A negative return from nextDelay means not to try again, in which
case the most recent failure exception is rethrown.

For example, a policy of incessant retrying would be expressed by:

class IncessantRetrying implements RetryPolicy {
    public boolean isFailureRecoverable(Exception e) { return true; }
    long nextDelay(long startTime, int retries) { return 0; }
}

Josh told me he'd be willing to distribute this more widely if there was
sufficient interest.

I've placed an incomplete draft of this code in a public area of the Java
Concurrency in Practice source repository:

https://dev.priorartisans.com/repos/jcip/trunk/src/main/jcip/retry/

It's incomplete because it doesn't define AbstractRetryPolicy.

What Bela describes is slightly different: each task can be submitted with
its own "RetryPolicy". That could be achieved within Josh's framework, for
example, by extending ScheduledThreadPoolExecutor and overriding
decorateTask to do the requisite wrapping for tasks that implement
RetryPolicy.

--tim

On 1/18/07, Bela Ban <belaban at yahoo.com> wrote:
>
>
>
> Ernst, Matthias wrote:
> > #2: In that case I'll have the tasks reschedule themselves:
> >
> > run() {
> >
> > ... pool.schedule(this, remaining);
> > }
>
> This is something I thought of too, but it is somewhat kludgy for a task
> to have knowledge of the pool and to reschedule itself. Although this is
> done in ScheduledThreadPoolExecutor.ScheduledFutureTask.runPeriodic() too:
>
> private void runPeriodic() {
>             boolean ok = ScheduledFutureTask.super.runAndReset();
>             boolean down = isShutdown();
>             // Reschedule if not cancelled and not shutdown or policy
> allows
>             if (ok && (!down ||
> (getContinueExistingPeriodicTasksAfterShutdownPolicy() &&
>                         !isTerminating()))) {
>                 long p = period;
>                 if (p > 0)
>                     time += p;
>                 else
>                     time = now() - p;
>                 *ScheduledThreadPoolExecutor.super.getQueue().add(this);
> // <<<<<==== here*
>             }
>             // This might have been the final executed delayed
>             // task.  Wake up threads to check.
>             else if (down)
>                 interruptIdleWorkers();
>         }
>
> It would be great if there was a scheduleXXX() method which took a Period
> parameter:
>
>     scheduleAtFixedRate(Runnable command, long initialDelay,  Period
> period, TimeUnit unit)
>
> with Period being
>
>     public interface Period {
>         long get();
>     }
>
> Then the code above would simple call:
>
>     long p = period.get();
>
>  rather than
>
>     long p = period;
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: /pipermail/attachments/20070120/e5a7973e/attachment.html 


More information about the Concurrency-interest mailing list