Handling exceptions from Java ExecutorService tasks Handling exceptions from Java ExecutorService tasks multithreading multithreading

Handling exceptions from Java ExecutorService tasks


WARNING: It should be noted that this solution will block the calling thread.


If you want to process exceptions thrown by the task, then it is generally better to use Callable rather than Runnable.

Callable.call() is permitted to throw checked exceptions, and these get propagated back to the calling thread:

Callable task = ...Future future = executor.submit(task);try {   future.get();} catch (ExecutionException ex) {   ex.getCause().printStackTrace();}

If Callable.call() throws an exception, this will be wrapped in an ExecutionException and thrown by Future.get().

This is likely to be much preferable to subclassing ThreadPoolExecutor. It also gives you the opportunity to re-submit the task if the exception is a recoverable one.


From the docs:

Note: When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method.

When you submit a Runnable, it'll get wrapped in a Future.

Your afterExecute should be something like this:

public final class ExtendedExecutor extends ThreadPoolExecutor {    // ...    protected void afterExecute(Runnable r, Throwable t) {        super.afterExecute(r, t);        if (t == null && r instanceof Future<?>) {            try {                Future<?> future = (Future<?>) r;                if (future.isDone()) {                    future.get();                }            } catch (CancellationException ce) {                t = ce;            } catch (ExecutionException ee) {                t = ee.getCause();            } catch (InterruptedException ie) {                Thread.currentThread().interrupt();            }        }        if (t != null) {            System.out.println(t);        }    }}


The explanation for this behavior is right in the javadoc for afterExecute:

Note: When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method.