[concurrency-interest] Request (bug fix?) for ScheduledThreadPoolExecutor

Tim Peierls tim at peierls.net
Mon Aug 8 19:27:29 EDT 2005


Norman Elton wrote:
> If I create a ThreadPoolExecutor that overrides the beforeExecute and  
> afterExecute methods, I see my Runnable go into the pool, and come  out. 
> This is very handy.
> 
> If I change to a ScheduledThreadPoolExecutor, the objects passed to  
> these methods are of type ScheduledFutureTask, not my original  objects. 
> Looking at the code, it appears that  ScheduledThreadPoolExecutor wraps 
> my Runnable inside this new object.
> 
> So the question is... Is this necessary? For immediate executions  
> (non-scheduled), could the internals of ScheduledThreadPoolExecutor  
> keep my Runnables intact, or provide some way to get them back after  
> execution?

TPE works in terms of execute(Runnable); the implementations of 
submit(Callable) and STPE.schedule(Runnable,...) wrap the Callable or 
scheduled Runnable to provide a return value and/or delayed execution -- this 
wrapped task has to be a Runnable so that TPE can execute it.

There is currently no standard way to map back from the wrapper to its 
contained Callable or Runnable, so beforeExecute and afterExecute get passed 
the wrapper Runnable.

But you can do this mapping yourself, for example, by storing the 
ScheduledFuture and associated Runnable in a Map when submitting:

     Map<Object, Runnable> map = ...;
     ScheduledFuture<?> f = ses.schedule(runnable, 100, MILLISECONDS);
     map.put(f, runnable);

Then in beforeExecute/afterExecute, you can look up the "real" Runnable:

     void beforeExecute(Thread t, Runnable r) {
         if (map.containsKey(r))
             r = map.get(r);
         // use r
     }

This is inconvenient, and it relies on a private implementation detail. But 
there is hope: JDK 6.0 is slated to provide protected methods that you can 
override to control the type of the returned wrapper, at which point this will 
all become a bit easier, because you can then use a custom wrapper that 
"knows" its original task.

     class MySTPE extends ScheduledThreadPoolExecutor {
         ...
         protected <V> RunnableScheduledFuture<V> decorateTask(
             Runnable runnable, RunnableScheduledFuture<V> task) {
             return new MyWrapper(runnable, task);
         }
     }

     class MyWrapper<V> implements RunnableScheduledFuture<V> {
         private final Runnable runnable;
         private final RunnableScheduledFuture<V> task;
         MyWrapper(Runnable runnable, RunnableScheduledFuture<V> task) {
             this.runnable = runnable;
             this.task = task;
         }
         public Runnable originalRunnable() { return runnable; }
         // ... delegate RunnableScheduledFuture methods to task
     }

     void beforeExecute(Thread t, Runnable r) {
         if (r instanceof MyWrapper)
             r = ((MyWrapper) r).originalRunnable();
         // use r
     }

--tim



More information about the Concurrency-interest mailing list