[concurrency-interest] Exception handling & Executors

Tim Peierls tim at peierls.net
Tue Oct 25 17:16:25 EDT 2005


Joe Bowbeer wrote:
> I meant:
>
> executor.execute(runnable)
>
> This gives you the most control over the actual task that is
> executing.  For example, your task could be a custom FutureTask with a
> done() method specialized for handling OOME.
>
> To isolate the impact, you could create a "task factory" that took a
> runnable and returned a FutureTask customized for OOME handling.
>
> Or (and this is probably the best solution for you) you could create a
> custom ExecutorService that did this for you, by extending
> AbstractExecutorService.

Specifically, with something like this:

   public OomeHandler {
       void handleOutOfMemoryError(OutOfMemoryError e);
   }

   public class OomeHandlingExecutorService extends AbstractExecutorService {
       private final ExecutorService exec;
       private final OomeHandler handler;
       public OomeHandlingExecutorService(ExecutorService exec, OomeHandler handler) {
           this.exec = exec;
       }
       public void execute(Runnable runnable) {
           exec.execute(runnable);
       }
       public <V> FutureTask<V> submit(Callable<V> callable) {
           if (callable == null) throw new NullPointerException();
           FutureTask<T> ftask = new OomeHandlingFutureTask<V>(callable);
           execute(ftask);
           return ftask;
       }
       public <V> FutureTask<V> submit(Runnable runnable, V result) {
           if (runnable == null) throw new NullPointerException();
           FutureTask<T> ftask = new OomeHandlingFutureTask<V>(runnable);
           execute(ftask);
           return ftask;
       }
       public FutureTask<?> submit(Runnable runnable) {
           if (runnable == null) throw new NullPointerException();
           FutureTask<Object> ftask = new OomeHandlingFutureTask<Object>(runnable, null);
           execute(ftask);
           return ftask;
       }

       // invokeAny/All and lifecycle methods all delegate to exec

       private static class OomeHandlingFutureTask<V> extends FutureTask {
           private final OomeHandler handler;
           OomeHandlingFutureTask(Callable<V> callable, OomeHandler handler) {
               super(callable);
               this.handler = handler;
           }
           OomeHandlingFutureTask(Runnable runnable, V result) {
               super(runnable, result);
               this.handler = handler;
           }
           protected void done() {
               try {
                   get();
               } catch (CancellationException e) {
                   // ignore
               } catch (ExecutionException e) {
                   Throwable t = e.getCause();
                   if (handler != null && t instanceof OutOfMemoryError)
                       handler.handleOutOfMemoryError((OutOfMemoryError) t);
               }
           }
       }
   }

Delegating the invokeAll and invokeAny methods above means that invoked tasks don't
get OOME handling. This can be addressed with copy-and-paste, but as Joe says:

> This sort of extension is made even easier in 1.6 Mustang with the
> addition of the newTaskFor method:
>
>     protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
>         return new FutureTask<T>(runnable, value);
>     }

For example, you could subclass TPE so that it returns OomeHandlingFutureTask, which is much more 
compact that the code above.

--tim



More information about the Concurrency-interest mailing list