Why exception is null in ThreadPoolExecutor's afterExecute()? Why exception is null in ThreadPoolExecutor's afterExecute()? multithreading multithreading

Why exception is null in ThreadPoolExecutor's afterExecute()?


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);}


This is an alternate way of doing it. Taking hint from here

package com.autonomy.introspect.service;import java.sql.SQLException;import java.util.concurrent.*;public class MyExecutor extends ThreadPoolExecutor {    public static void main(String[] args) {        MyExecutor threadPool = new MyExecutor();        Task<Object> task = new Task<Object>();        Future<Object> futureTask = threadPool.submit(task);        try {            System.out.println(futureTask.get());        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            System.out.println("exception thrown: " + e.getMessage());        }    }    public MyExecutor() {        super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(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..");        }    }}

The usage of afterExecute is for a different purpose.

This class provides protected overridable beforeExecute(java.lang.Thread,java.lang.Runnable) and afterExecute(java.lang.Runnable, java.lang.Throwable) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated() can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.If hook or callback methods throw exceptions, internal worker threads may 

in turn fail and abruptly terminate.