I want to handle exeptions thrown by worker threads in ThreadPoolExecutor#afterExecute()
method. Currently I have this code:
public class MyExecutor extends ThreadPoolExecutor {
public static void main(String[] args) {
MyExecutor threadPool = new MyExecutor();
Task<Object> task = new Task<>();
threadPool.submit(task);
}
public MyExecutor() {
super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4000));
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
System.out.println("in afterExecute()");
if (t != null) {
System.out.println("exception thrown: " + t.getMessage());
} else {
System.out.println("t == null");
}
}
private static class Task<V> implements Callable<V> {
@Override
public V call() throws Exception {
System.out.println("in call()");
throw new SQLException("testing..");
}
}
}
If I run the code I get output:
in call()
in afterExecute()
t == null
Why is parameter Throwable t
null
in afterExecute()
? Shouldn't it be the SQLException
instance?
This is actually expected behaviour.
Quoting afterExecute
Javadoc:
If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.
This means the throwable instance will be RuntimeException
or Error
, not checked Exception
. Since SQLException
is a checked exception, it won't be passed to afterExecute
.
There is also something else going on here (still quoting the Javadoc):
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.
In your example, the task is enclosed in a FutureTask
since you are submitting a Callable
, so you are in this case. Even in you change your code to throw a RuntimeException
, if won't be given to afterExecute
. The Javadoc gives a sample code to deal with this, which I'm copying here, for reference:
protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t == null && r instanceof Future) { try { Object result = ((Future) r).get(); } catch (CancellationException ce) { t = ce; } catch (ExecutionException ee) { t = ee.getCause(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // ignore/reset } } if (t != null) System.out.println(t); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With