Why is UncaughtExceptionHandler not called by ExecutorService?

JavaMultithreading

Java Problem Overview


I've stumbled upon a problem, that can be summarized as follows:

When I create the thread manually (i.e. by instantiating java.lang.Thread) the UncaughtExceptionHandler is called appropriately. However, when I use an ExecutorService with a ThreadFactory the handler is ommited. What did I miss?

public class ThreadStudy {

private static final int THREAD_POOL_SIZE = 1;

public static void main(String[] args) {
	
	// create uncaught exception handler
	
	final UncaughtExceptionHandler exceptionHandler = new UncaughtExceptionHandler() {
		
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			synchronized (this) {
				System.err.println("Uncaught exception in thread '" + t.getName() + "': " + e.getMessage());
			}
		}
	};
	
	// create thread factory
	
	ThreadFactory threadFactory = new ThreadFactory() {
		
		@Override
		public Thread newThread(Runnable r) {
			// System.out.println("creating pooled thread");
			final Thread thread = new Thread(r);
			thread.setUncaughtExceptionHandler(exceptionHandler);
			return thread;
		}
	};
	
	// create Threadpool
	
	ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE, threadFactory);
	
	// create Runnable
	
	Runnable runnable = new Runnable() {
		
		@Override
		public void run() {
			// System.out.println("A runnable runs...");
			throw new RuntimeException("Error in Runnable");
		}
	};
	
	// create Callable
	
	Callable<Integer> callable = new Callable<Integer>() {
		
		@Override
		public Integer call() throws Exception {
			// System.out.println("A callable runs...");
			throw new Exception("Error in Callable");
		}
	};
	
	// a) submitting Runnable to threadpool
	threadPool.submit(runnable);
	
	// b) submit Callable to threadpool
	threadPool.submit(callable);
	
	// c) create a thread for runnable manually
	final Thread thread_r = new Thread(runnable, "manually-created-thread");
	thread_r.setUncaughtExceptionHandler(exceptionHandler);
	thread_r.start();
	
	threadPool.shutdown();
	System.out.println("Done.");
}
}

I expect: Three times the message "Uncaught exception..."

I get: The message once (triggered by the manually created thread).

Reproduced with Java 1.6 on Windows 7 and Mac OS X 10.5.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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"

Solution 4 - Java

I just browsed through my old questions and thought I might share the solution I implemented in case it helps someone (or I missed a bug).

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;


/**
 * @author Mike Herzog, 2009
 */
public class ExceptionHandlingExecuterService extends ScheduledThreadPoolExecutor {
	
	/** My ExceptionHandler */
	private final UncaughtExceptionHandler exceptionHandler;
	
	/**
	 * Encapsulating a task and enable exception handling.
	 * <p>
	 * <i>NB:</i> We need this since {@link ExecutorService}s ignore the
	 * {@link UncaughtExceptionHandler} of the {@link ThreadFactory}.
	 * 
	 * @param <V> The result type returned by this FutureTask's get method.
	 */
	private class ExceptionHandlingFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {
		
		/** Encapsulated Task */
		private final RunnableScheduledFuture<V> task;
		
		/**
		 * Encapsulate a {@link Callable}.
		 * 
		 * @param callable
		 * @param task
		 */
		public ExceptionHandlingFutureTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
			super(callable);
			this.task = task;
		}
		
		/**
		 * Encapsulate a {@link Runnable}.
		 * 
		 * @param runnable
		 * @param result
		 * @param task
		 */
		public ExceptionHandlingFutureTask(Runnable runnable, RunnableScheduledFuture<V> task) {
			super(runnable, null);
			this.task = task;
		}
		
		/*
		 * (non-Javadoc)
		 * @see java.util.concurrent.FutureTask#done() The actual exception
		 * handling magic.
		 */
		@Override
		protected void done() {
			// super.done(); // does nothing
			try {
				get();
				
			} catch (ExecutionException e) {
				if (exceptionHandler != null) {
					exceptionHandler.uncaughtException(null, e.getCause());
				}
				
			} catch (Exception e) {
				// never mind cancelation or interruption...
			}
		}
		
		@Override
		public boolean isPeriodic() {
			return this.task.isPeriodic();
		}
		
		@Override
		public long getDelay(TimeUnit unit) {
			return task.getDelay(unit);
		}
		
		@Override
		public int compareTo(Delayed other) {
			return task.compareTo(other);
		}
		
	}
	
	/**
	 * @param corePoolSize The number of threads to keep in the pool, even if
	 *        they are idle.
	 * @param eh Receiver for unhandled exceptions. <i>NB:</i> The thread
	 *        reference will always be <code>null</code>.
	 */
	public ExceptionHandlingExecuterService(int corePoolSize, UncaughtExceptionHandler eh) {
		super(corePoolSize);
		this.exceptionHandler = eh;
	}
	
	@Override
	protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
		return new ExceptionHandlingFutureTask<V>(callable, task);
	}
	
	@Override
	protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
		return new ExceptionHandlingFutureTask<V>(runnable, task);
	}
}

Solution 5 - Java

In addition to Thilos answer: I've written a post about this behavior, if one wants to have it explained a little bit more verbose: https://ewirch.github.io/2013/12/a-executor-is-not-a-thread.html.

Here is a excerpts from the article:

> A Thread is capable of processing only one Runable in general. When the Thread.run() method exits the Thread dies. The ThreadPoolExecutor implements a trick to make a Thread process multiple Runnables: it uses a own Runnable implementation. The threads are being started with a Runnable implementation which fetches other Runanbles (your Runnables) from the ExecutorService and executes them: ThreadPoolExecutor -> Thread -> Worker -> YourRunnable. When a uncaught exception occurs in your Runnable implementation it ends up in the finally block of Worker.run(). In this finally block the Worker class tells the ThreadPoolExecutor that it “finished” the work. The exception did not yet arrive at the Thread class but ThreadPoolExecutor already registered the worker as idle. > > And here’s where the fun begins. The awaitTermination() method will be invoked when all Runnables have been passed to the Executor. This happens very quickly so that probably not one of the Runnables finished their work. A Worker will switch to “idle” if a exception occurs, before the Exception reaches the Thread class. If the situation is similar for the other threads (or if they finished their work), all Workers signal “idle” and awaitTermination() returns. The main thread reaches the code line where it checks the size of the collected exception list. And this may happen before any (or some) of the Threads had the chance to call the UncaughtExceptionHandler. It depends on the order of execution if or how many exceptions will be added to the list of uncaught exceptions, before the main thread reads it. > > A very unexpected behavior. But I won’t leave you without a working solution. So let’s make it work. > > We are lucky that the ThreadPoolExecutor class was designed for extensibility. There is a empty protected method afterExecute(Runnable r, Throwable t). This will be invoked directly after the run() method of our Runnable before the worker signals that it finished the work. The correct solution is to extend the ThreadPoolExecutor to handle uncaught exceptions: > > public class ExceptionAwareThreadPoolExecutor extends ThreadPoolExecutor { > private final List uncaughtExceptions = > Collections.synchronizedList(new LinkedList()); >
> @Override > protected void afterExecute(final Runnable r, final Throwable t) { > if (t != null) uncaughtExceptions.add(t); > } >
> public List getUncaughtExceptions() { > return Collections.unmodifiableList(uncaughtExceptions); > } > }

Solution 6 - Java

There is a little bit of a workaround. In your run method, you can catch every exception, and later on do something like this (ex: in a finally block)

Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);
//or, same effect:
Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ex);
 

This will "ensure a firing" of the current exception as thrown to your uncoughtExceptionHandler (or to the defualt uncought exception handler). You can always rethrow catched exceptions for pool worker.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDerMikeView Question on Stackoverflow
Solution 1 - JavaThiloView Answer on Stackoverflow
Solution 2 - JavaJan TrienesView Answer on Stackoverflow
Solution 3 - JavaChaojun ZhongView Answer on Stackoverflow
Solution 4 - JavaDerMikeView Answer on Stackoverflow
Solution 5 - JavaEduard WirchView Answer on Stackoverflow
Solution 6 - JavaAntoniossssView Answer on Stackoverflow