Why is UncaughtExceptionHandler not called by ExecutorService?

Exceptions which are thrown by tasks submitted to ExecutorService#submit get wrapped into an ExcecutionException and are rethrown by the Future.get() method. This is, because the executor considers the exception as part of the result of the task.

If you however submit a task via the execute() method which originates from the Executor interface, the UncaughtExceptionHandler is notified.


Quote from the book Java Concurrency in Practice(page 163),hope this helps

Somewhat confusingly, exceptions thrown from tasks make it to the uncaught exception handler only for tasks submitted with execute; for tasks submitted with submit, any thrown exception, checked or not, is considered to be part of the task’s return status. If a task submitted with submit terminates with an exception, it is rethrown by Future.get, wrapped in an ExecutionException.

Here is the example:

public class Main {

public static void main(String[] args){


    ThreadFactory factory = new ThreadFactory(){

        @Override
        public Thread newThread(Runnable r) {
            // TODO Auto-generated method stub
            final Thread thread =new Thread(r);

            thread.setUncaughtExceptionHandler( new Thread.UncaughtExceptionHandler() {

                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    // TODO Auto-generated method stub
                    System.out.println("in exception handler");
                }
            });

            return thread;
        }

    };

    ExecutorService pool=Executors.newSingleThreadExecutor(factory);
    pool.execute(new testTask());

}



private static class TestTask implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        throw new RuntimeException();
    }

}

I use execute to submit the task and the console outputs "in exception handler"


Because the exception does not go uncaught.

The Thread that your ThreadFactory produces is not given your Runnable or Callable directly. Instead, the Runnable that you get is an internal Worker class, for example see ThreadPoolExecutor$Worker. Try System.out.println() on the Runnable given to newThread in your example.

This Worker catches any RuntimeExceptions from your submitted job.

You can get the exception in the ThreadPoolExecutor#afterExecute method.