Reference: advanced-exception-handling
Reference: https://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601
- interface for handlers invoked when a
Thread
abruptly terminates due to an uncaught exception.
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
- per-thread basis
thread.setUncaughtExceptionHandler(...)
thread.getUncaughtExceptionHandler()
- default
Thread.setDefaultUncaughtExceptionHandler(...)
Thread.getDefaultUncaughtExceptionHandler()
- from
Thread
class// null unless explicitly set private volatile UncaughtExceptionHandler uncaughtExceptionHandler; // null unless explicitly set private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
- is represented by
ThreadGroup
class thread.getThreadGroup()
- a thread is always a member of a thread group
- by default, the thread group is inherited from creator thread
- the JVM creates a thread group called
main
and a thread in this group calledmain
, which is responsible for running themain()
at startup - thread groups are arranged in a tree-like structure
- thread group
main
does not have a parent ThreadGroup implements Thread.UncaughtExceptionHandler
When thread terminates due to an uncaught exception:
- (first per-thread basis): if
thread.getUncaughtExceptionHandler()
is not null, its methoduncaughtException(Thread t, Throwable e)
is called - otherwise, (second per-
ThreadGroup
basis): thread group methoduncaughtException(Thread t, Throwable e)
is called - ifuncaughtException
method is not@Override
,uncaughtException
is called recursively in the consecutive parents (note thatmain
parent isnull
) - (bubbles up to the top-level): top-level thread group handler delegates to the default system handler
Thread.getDefaultUncaughtExceptionHandler()
(if one exists; the default is none) and otherwise prints the stack trace to the consoleSystem.err
We will provide simple examples of how to handle uncaught exceptions thrown in threads.
- handler for a specific thread
and test:
final class SpecificUncaughtExceptionsHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught specific: " + e + " in: " + t.getName()); } }
will print:var thread = new Thread(endsExceptionally); thread.setUncaughtExceptionHandler(new SpecificUncaughtExceptionsHandler()); thread.start(); thread.join();
Caught specific: java.lang.RuntimeException: exception! in: Thread-0
- global handler
and test:
final class GlobalUncaughtExceptionsHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught global: " + e + " in: " + t.getName()); } }
will print:Thread.setDefaultUncaughtExceptionHandler(new GlobalUncaughtExceptionsHandler()); var thread = new Thread(endsExceptionally); thread.start(); thread.join();
Caught global: java.lang.RuntimeException: exception! in: Thread-0
- group handler
and tests:
final class MyThreadGroup extends ThreadGroup { MyThreadGroup() { super("My Thread Group"); } @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("Caught in My Thread Group: " + e + " in: " + t.getName()); } }
will print:var t = new Thread(new MyThreadGroup(), endsExceptionally); t.start(); t.join();
Caught in My Thread Group: java.lang.RuntimeException: exception! in: Thread-0
- unhandled at all
will print:
var thread = new Thread(endsExceptionally); thread.start(); thread.join();
Exception in thread "Thread-0" java.lang.RuntimeException: exception! at ThreadExceptionTest.lambda$new$0(ThreadExceptionTest.java:8) at java.base/java.lang.Thread.run(Thread.java:834)