Skip to content
Advertisement

Java Swing: SwingWorker uncaught exceptions are not getting picked up by Thread.UncaughtExceptionHandler

My Swing program creates many threads and it’s getting hard to handle exceptions properly. I would like to rely on a global exception handler, and i came across

Thread.UncaughtExceptionHandler

Everything seemed to work fine, until i introduced a SwingWorker to perform a background task. Apparently, if an exception occurs inside my swing worker and it is not handled inside it, the exception will not be picked up by Thread.UncaughtExceptionHandler

This is a small snippet to test this behaviour:

import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class SwingWorkerAndDefaultUncaughtExceptionHandler {

    MyTask task = new MyTask();

    public SwingWorkerAndDefaultUncaughtExceptionHandler() {
        Thread.setDefaultUncaughtExceptionHandler(new CentralizedExceptionHandler());
        task.execute();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new SwingWorkerAndDefaultUncaughtExceptionHandler();
            }
        });
    }

    private class MyTask extends SwingWorker<Void, Void> {
        @Override
        protected Void doInBackground() {
            System.out.println("doInBackGround invoked");
            Integer i = null;
            System.out.println(i.doubleValue());
            System.out.println("This line is not reached");
            return null;
        }

        @Override
        protected void done() {
            System.out.println("done invoked");
        }
    }

    public static class CentralizedExceptionHandler implements Thread.UncaughtExceptionHandler {

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("This line is not reached either");
        }
    }

Am i missing something here? Is there something i can set on my swingworker to behave as expected?

Advertisement

Answer

The javax.swing.SwingWorker#SwingWorker is using a java.util.concurrent.FutureTask to execute the work provided in the method doInBackground.

In java.util.concurrent.FutureTask#run we can see that any exceptions are caught, and set as the result state of the FutureTask via setException:

try {
    result = c.call();
    ran = true;
} catch (Throwable ex) {
    result = null;
    ran = false;
    setException(ex);
}

So in effect, this means that there are no uncaught exceptions bubbeling up from the executor Threads, and thus it’s logical that your DefaultUncaughtExceptionHandler is not used.

You’re going to have to add your own exception handling to the worker, for that you can see the following references:

There are a few options from these references:

  • directly handle the exception in your worker, or
  • add a property change listener to check when the task is done; javax.swing.SwingWorker#addPropertyChangeListener
  • and then retrieve the execution result of the task via javax.swing.SwingWorker#get() or javax.swing.SwingWorker#get(long, java.util.concurrent.TimeUnit)
6 People found this is helpful
Advertisement