I have the following code that I expect to run successfully to completion but the code fails at the line "fail("this should not be reached");". Can someone please explain why the default uncaught exception handler is not called:
public class UncaughtExceptionTest extends TestCase
implements UncaughtExceptionHandler {
private final List<Throwable> uncaughtExceptions =
new CopyOnWriteArrayList<Throwable>();
class UncaughtExceptionTestInnerClass implements Runnable {
private final ScheduledThreadPoolExecutor executor =
new ScheduledThreadPoolExecutor(1);
private final CountDownLatch latch;
UncaughtExceptionTestInnerClass(CountDownLatch latch) {
this.latch = latch;
executor.schedule(this, 50, TimeUnit.MILLISECONDS);
}
@Override
public void run() {
System.out.println("This is printed");
fail("this should fail");
latch.countDown();
}
}
@Test
public void testUncaughtExceptions() {
Thread.setDefaultUncaughtExceptionHandler(this);
CountDownLatch latch = new CountDownLatch(1);
UncaughtExceptionTestInnerClass testTheInnerClass =
new UncaughtExceptionTestInnerClass(latch);
try {
if (!latch.await(1, TimeUnit.SECONDS)) {
if (uncaughtExceptions.size() > 0) {
Throwable exception = uncaughtExceptions.get(0);
System.out.println("First uncaught exception: " +
exception.getMessage());
}
else {
fail("this should not be reached");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void uncaughtException(Thread t, Throwable e) {
uncaughtExceptions.add(e);
}
}
Exception handling in Thread : By default run() method doesn't throw any exception, so all checked exceptions inside the run method has to be caught and handled there only and for runtime exceptions we can use UncaughtExceptionHandler.
You can use UncaughtExceptionHandler to handle the exception those causes a thread to terminate abruptly. Java doc for UncaughtExceptionHandler - Interface for handlers invoked when a Thread abruptly terminates due to an uncaught exception.
When an uncaught exception occurs, the JVM does the following: it calls a special private method, dispatchUncaughtException(), on the Thread class in which the exception occurs; it then terminates the thread in which the exception occurred1.
When an uncaught exception occurs, the JVM calls a special private method known dispatchUncaughtException( ), on the Thread class in which the exception occurs and terminates the thread. The Division by zero exception is one of the example for uncaught exceptions.
It has to do with the fact you're using an Executor to run the task. The uncaught exception handler is invoked only if the thread is about to be terminated due to an uncaught exception. If you change your implementation to use a plain thread so that the thread will terminate with the exception, you will see the expected behavior.
Depending on how you submit tasks, the executor thread may catch all Throwables and handle them. Therefore, the thread does not terminate due to these exceptions, and thus the uncaught exception handler does not get involved. For example, ThreadPoolExecutor.execute(Runnable) will trigger the uncaught exception handler. However, ThreadPoolExecutor.submit(Callable) does not. Also, ScheduledThreadPoolExecutor.schedule() does not either (it has to do with their use of FutureTask for implementation).
A better way of accessing unexpected exceptions with an executor service is via Future.
ScheduledThreadPoolExecutor.schedule()
takes a Runnable
/Callable
argument, not Thread
. The former don't have runtime exception handlers. Have a try
/catch
block for a RuntimeException
in your run
or call
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With