Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is UncaughtExceptionHandler not called by ExecutorService?

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.

like image 399
DerMike Avatar asked Dec 03 '09 10:12

DerMike


People also ask

Can you give an example for ExecutorService?

Here is an example of executing a Runnable with an ExecutorService : ExecutorService executorService = Executors. newSingleThreadExecutor(); executorService. execute(new Runnable() { public void run() { System.

Can threads be submitted to ExecutorService?

We use the Executors. newSingleThreadExecutor() method to create an ExecutorService that uses a single worker thread for executing tasks. If a task is submitted for execution and the thread is currently busy executing another task, then the new task will wait in a queue until the thread is free to execute it.

What is ExecutorService and how its works?

ExecutorService is a JDK API that simplifies running tasks in asynchronous mode. Generally speaking, ExecutorService automatically provides a pool of threads and an API for assigning tasks to it.


2 Answers

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.

like image 67
Thilo Avatar answered Sep 22 '22 06:09

Thilo


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.

like image 24
Jan Trienes Avatar answered Sep 24 '22 06:09

Jan Trienes