Java Programming Tutorials

Java programming tutorials with many code examples!

Java Thread UncaughtExceptionHandler

Problem:

How to handle exceptions in Java Thread? Since Java 5 the way to go is Thread UncaughtExceptionHandler, which we’re going to show in this post.

Solution:

In the below code we create and run a Thread that will throw an exception. When we try to catch the exception in the code that starts the exception nothing happens – the exception cannot be caught this way:

public static void main(String[] args) {
    try {
        new ExceptionalThread().start();
    } catch (Exception e) {
        System.out.println("Got exception: " + e);
    }
}

ExceptionalThread class is defined in the code below.

Here’s the result of running the above code:

Starting work in thread: 10
Exception in thread "Thread-0" java.lang.RuntimeException: An Exception that ends the thread: 10
      at com.farenda.java.lang.ThreadUncaughtExceptionHandlerExample$ExceptionalThread.run(ThreadUncaughtExceptionHandlerExample.java:31)

As you can see there’s no “Got exception” in the output and the exception got printed to standard output, which is the default behavior.

To fix that and handle exceptions uncaught by threads Java provides a mechanism of UncaughtExceptionHandler. You can obtain default handler using static method Thread.getDefaultUncaughtExceptionHandler(). The default handler is fine for many situations, but sometimes (for example in GUI application) we would like to collect such information and act appropriately. To do that you can set own handler for threads. It can be done in a few ways:

  • void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
    That allows to set per thread handler.
  • static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
    To set default handler for Threads, which will be active when they don’t have their own handler.

In the following example we’ll show both ways – per thread and default. Our MyUncaughtExceptionHandler just collects thrown exceptions for further processing:

package com.farenda.java.lang;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class ThreadUncaughtExceptionHandlerExample {

    public static class MyUncaughtExceptionHandler
            implements Thread.UncaughtExceptionHandler {

        private List<String> errors = new LinkedList<>();

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            String message = String.format("Thread %s hit by exception %s.",
                    t.getName(), e.toString());
            System.out.println(message);
            errors.add(message);
        }
    }

    private static class ExceptionalThread extends Thread {
        @Override
        public void run() {
            System.out.println("Starting work in thread: " + getId());
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                //ignore
            }
            // throw an exception when thread ID is even:
            if ((getId() % 2) == 0) {
                throw new RuntimeException("An Exception that ends the thread: "
                        + getId());
            } else {
                System.out.printf("Thread %d finished normally.%n", getId());
            }
        }
    }

    public static void main(String[] args) {
        MyUncaughtExceptionHandler handler = new MyUncaughtExceptionHandler();

        startThreadsWithPerThreadHandler(handler);
        printResults(handler);

        System.out.println("\nClearing errors in handler.\n");
        handler.errors.clear();

        startThreadsWithDefaultHandler(handler);
        printResults(handler);
    }

    private static void startThreadsWithDefaultHandler(
            MyUncaughtExceptionHandler handler) {
        System.out.println("Setting default uncaught exception handler.");
        Thread.setDefaultUncaughtExceptionHandler(handler);
        System.out.println("Starting threads");
        for (int i = 0; i < 5; ++i) {
            new ExceptionalThread().start();
        }
    }

    private static void startThreadsWithPerThreadHandler(
            MyUncaughtExceptionHandler handler) {
        System.out.println("Starting threads with per thread uncaught exception handler");
        for (int i = 0; i < 5; ++i) {
            ExceptionalThread command = new ExceptionalThread();
            command.setUncaughtExceptionHandler(handler);
            command.start();
        }
    }

    private static void printResults(MyUncaughtExceptionHandler handler) {
        try {
            System.out.println("Waiting a bit for threads to finish...");
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            // ignore
        }

        System.out.println("\nCaught errors:");
        handler.errors.forEach(System.out::println);
    }
}
&#91;/sourcecode&#93;

<p> The code is straightforward. In <b>startThreadsWithDefaultHandler()</b> we set default handler for all threads and in <b>startThreadsWithPerThreadHandler()</b> we set it per thread basis, so we could set different handlers for them. </p>

<p> And the result of running the above code: </p>


Starting threads with per thread uncaught exception handler
Starting work in thread: 10
Starting work in thread: 11
Starting work in thread: 12
Starting work in thread: 13
Waiting a bit for threads to finish...
Starting work in thread: 14
Thread 11 finished normally.
Thread Thread-4 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 14.
Thread 13 finished normally.
Thread Thread-2 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 12.
Thread Thread-0 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 10.

Caught errors:
Thread Thread-4 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 14.
Thread Thread-2 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 12.
Thread Thread-0 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 10.

Clearing errors in handler.

Setting default uncaught exception handler.
Starting threads
Starting work in thread: 16
Starting work in thread: 17
Starting work in thread: 15
Starting work in thread: 18
Waiting a bit for threads to finish...
Starting work in thread: 19
Thread 17 finished normally.
Thread 15 finished normally.
Thread 19 finished normally.
Thread Thread-6 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 16.
Thread Thread-8 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 18.

Caught errors:
Thread Thread-6 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 16.
Thread Thread-8 hit by exception java.lang.RuntimeException: An Exception that ends the thread: 18.

As you can see even threads thrown exceptions, which have been collected in MyUncaughtExceptionHandler error list. The list have been printed in printResults() method, but we could process them and show to users or create a report and send an email to admins.

In this post we haven’t covered one thing – how to set UncaughtExceptionHandler when ExecutorService is used. We’ll show that in the next post, so stay tuned. :-)

Share with the World!