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:
- Graceful exception handling in Swing Worker
- How should I handle exceptions when using SwingWorker?
- The proper way to handle exceptions thrown by the SwingWorker.doInBackground
- SwingWorker exceptions lost even when using wrapper classes
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()
orjavax.swing.SwingWorker#get(long, java.util.concurrent.TimeUnit)