I borrowed this from another question:
@Slf4j
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
public void run() {
try {
//do some stuff
LOG.debug("about to throw a RE from a worker thead");
} catch (Exception e) {
e.printStackTrace();
}
throw new RuntimeException("purposeful!");
}
};
LOG.debug("in main thead");
t.setUncaughtExceptionHandler(
(thread, throwable) -> LOG.debug("in main thread; catching exception from worker. uncaught exception from worker thread: {} from {}",
throwable.getMessage(), thread.getName()));
t.start();
TimeUnit.SECONDS.sleep(10);
LOG.debug("done-main thead");
}
}
If it runs, the following output is produced:
10:19:50.249 [main] DEBUG com.foo.services.search.Main - in main thead
10:19:50.258 [Thread-0] DEBUG com.foo.services.search.Main - about to throw a RE from a worker thead
10:19:50.258 [Thread-0] DEBUG com.foo.services.search.Main - in main thread; catching exception from worker. uncaught exception from worker thread: purposeful! from Thread-0
10:20:00.258 [main] DEBUG com.foo.services.search.Main - done-main thead
Why, when thread-0 is finished, does the throwable-catching-activity appear to be occurring inside this completed thread?
CodePudding user response:
Form doc of JDK, it is stated that this method is only called by the JVM:
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
Out of curiosity, I found the relevant source code for hotspot: https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/thread.cpp
As you can see in the thread.cpp
, this logic is triggered when thread
exit:
// For any new cleanup additions, please check to see if they need to be applied to
// cleanup_failed_attach_current_thread as well.
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// ........
if (!destroy_vm) {
if (uncaught_exception.not_null()) {
EXCEPTION_MARK;
// Call method Thread.dispatchUncaughtException().
Klass* thread_klass = vmClasses::Thread_klass();
//...
}