Exception Handling in Threads
09 Jan 2017 Java #java #threadsBy contract, Runnable#run method does not allow throwing exceptions. Possible ways of handling exceptions are try/catch blocks or setting exception handler on thread or thread group.
A thread or thread group allows us to set an exception handler on it, to receive exceptions occured during the execution of thread.
How it works
If you are clever enough, following flowchart says it all. Have a look!
Example
Create a general ExceptionalThread class which inherits from Thread and generates ArrayIndexOutOfBoundsException when run. See the code below
class ExceptionalThread extends Thread {
ExceptionalThread(String name) {
super(name);
}
ExceptionalThread(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
super.run();
// generates ArrayIndexOutOfBoundsException
final int unused = (new int[2])[3];
System.out.println(unused);
} // run
} // ExceptionalThreadInherit 3 more classes from this class with names DefaultHandler, ThreadGroupHandler, ThreadSpecificHandler.
-
ThreadSpecificHandlerthread sets itsUncaughtExceptionHandlerand exception will be caught in this handler. -
ThreadGroupHandlerthread callsuncaughtExceptionmethod of its thread group. -
DefaultHandlerthread callsDefaultUncaughtExceptionHandlerof the thread.
Code for all three classes is given below
ThreadSpecificHandler
class ThreadSpecificHandler extends ExceptionalThread {
ThreadSpecificHandler() {
super("ThreadSpecificHandler");
}
} // ThreadSpecificHandlerThreadGroupHandler
class ThreadGroupHandler extends ExceptionalThread {
ThreadGroupHandler(ThreadGroup tg) {
super(tg, "ThreadGroupHandler");
}
} // ThreadGroupHandlerDefaultHandler
class DefaultHandler extends ExceptionalThread {
DefaultHandler() {
super("DefaultHandler");
}
@Override
public void run() {
Thread.setDefaultUncaughtExceptionHandler((t, e) -> App.exceptionHandler(t, e, "Thread#UncaughtExceptionHandler (Default)"));
super.run();
}
} // DefaultHandlerApp
public class App {
static void exceptionHandler(Thread t, Throwable exp, String method){
System.out.println(String.format("Method: %s - ThreadName: %s - Exception: %s", method, t.getName(), exp.getClass().getSimpleName()));
} // exceptionHandler
public static void main(String[] args) throws InterruptedException {
Thread threadWithHandler = new ThreadSpecificHandler();
threadWithHandler.setUncaughtExceptionHandler((t, e) -> exceptionHandler(t, e, "Thread#UncaughtExceptionHandler"));
threadWithHandler.start();
/* ------------------- THREAD GROUP ---------------*/
ThreadGroup group = new ThreadGroup("exp"){
@Override
public void uncaughtException(Thread t, Throwable e) {
exceptionHandler(t, e, "ThreadGroup#uncaughtException");
}
};
/* ------------------- THREAD GROUP ---------------*/
Thread threadWithGroupHandler = new ThreadGroupHandler(group);
threadWithGroupHandler.start();
Thread threadWithDefaultHandler = new DefaultHandler();
threadWithDefaultHandler.start();
// wait for threads
threadWithDefaultHandler.join();
threadWithGroupHandler.join();
threadWithHandler.join();
} // main
} // AppOutput
Method: ThreadGroup#uncaughtException - ThreadName: ThreadGroupHandler - Exception: ArrayIndexOutOfBoundsException
Method: Thread#UncaughtExceptionHandler (Default) - ThreadName: DefaultHandler - Exception: ArrayIndexOutOfBoundsException
Method: Thread#UncaughtExceptionHandler - ThreadName: ThreadSpecificHandler - Exception: ArrayIndexOutOfBoundsException