Java Programming Tutorials

Java programming tutorials with many code examples!

Java UncaughtExceptionHandler with ExecutorService

Problem:

How to set UncaughtExceptionHandler per Java Thread when working with Executorservice? This can be tricky, but we show a nice solution using ThreadFactory with ExecutiorService.

Solution:

In the previous post (Java Thread UncaughtExceptionHandler) we’ve shown how to set UncaughtExceptionHandler when creating threads manually. In this post we’ll show how to do it when one wants to use ExecutorService for threads management.

To be able set UncaughtExceptionHandler per thread we need to create a Java ThreadFactory, which will create threads and set the handler for each Thread. Then we just stop ExecutorService and print all errors collected by the exception handler:

package com.farenda.java.lang;

import com.farenda.java.lang.ThreadUncaughtExceptionHandlerExample.MyUncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class ThreadUncaughtExceptionHandlerExecutorService {

    public static class ExceptionalTask implements Runnable {
        private static int ntasks = 0;
        private int taskId = ++ntasks;

        @Override
        public void run() {
            System.out.println("Starting work in thread: " + taskId);
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                //ignore
            }
            if ((taskId % 2) == 0) {
                throw new RuntimeException("An Exception that ends task: " + taskId);
            } else {
                System.out.printf("Task %d finished normally.%n", taskId);
            }
        }
    }

    private static class CaughtExceptionsThreadFactory implements ThreadFactory {
        private MyUncaughtExceptionHandler handler = new MyUncaughtExceptionHandler();

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setUncaughtExceptionHandler(handler);
            return t;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        CaughtExceptionsThreadFactory threadFactory = new CaughtExceptionsThreadFactory();
        ExecutorService executor = Executors.newCachedThreadPool(threadFactory);

        System.out.println("Executing tasks:");
        for (int i = 0; i < 5; ++i) {
            executor.execute(new ExceptionalTask());
        }

        System.out.println("Shutting down the executor.");
        // we'll wait for two seconds, just to have clean output
        executor.awaitTermination(2, TimeUnit.SECONDS);

        printResults(threadFactory.handler);
    }

    private static void printResults(MyUncaughtExceptionHandler handler) {
        System.out.println("\nCaught errors:");
        handler.getErrors().forEach(System.out::println);
    }
}

Here’s the output of running the above code:

Executing tasks:
Starting work in thread: 1
Starting work in thread: 2
Starting work in thread: 3
Starting work in thread: 4
Shutting down the executor.
Starting work in thread: 5
Task 1 finished normally.
Thread Thread-3 hit by exception java.lang.RuntimeException: An Exception that ends task: 4.
Thread Thread-1 hit by exception java.lang.RuntimeException: An Exception that ends task: 2.
Task 5 finished normally.
Task 3 finished normally.

Caught errors:
Thread Thread-3 hit by exception java.lang.RuntimeException: An Exception that ends task: 4.
Thread Thread-1 hit by exception java.lang.RuntimeException: An Exception that ends task: 2.

Pretty straightforward. The only thing to remember is that when we want to set UncaughtExceptionHandler per thread we have to provide own ThreadFactory, in which we do that. Another approach would be to use static Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler) to set the default handler for all threads. Chosen solution depends on what you need.

Share with the World!
  • Hi! you can also set Thread.setDefaultUncaughtExceptionHandler generally for all threads then you don’t need to use custom ThreadFactory.

    • Hi Daniel!
      That’s correct and this is what I wrote at the end of the article (probably I should make it more visible). Anyway, which approach you choose depends on your needs.