UncaughtExceptionHandler
线程的run方法不能抛出任何检查型的异常,但是非检查型的异常可能会导致线程终止,在这种情况下,线程会死亡,也会导致主线程异常终止。
对于可以传播的异常,在线程死亡之前,异常会传递到一个用于处理未捕获异常的处理器。前提是这个处理器必须是一个实现了Thread.UncaughtExceptionHandler
接口的类。
这些话是什么意思呢,继续往下看。
关于检查型异常和非检查型异常如果有点模糊,可以参考我的这两篇博文:
Exception必知必会 三种try语句的用法
Checked Exceptions:Java最大的一个错误
如下,如果我在run方法中强行抛出异常,会报错。

所以在线程中遇到异常了,我们只能用try-catch
尽可能将异常给捕获住。

但是在每个线程的run方法里,我们不可能将每一句代码都包裹在一个大大地try-catch
代码块中吧。检查型异常我们不得不用try-catch代码块包裹住,但是非检查型异常也有不少,我们不能保证非检查型异常不出错,但是将非检查型异常都使用try-catch
包裹住也不恰当。
请看下面这段代码。
第一段代码:
package concurrence;
public class UncaughtExceptionHandlerTest {
public static void main(String[] args) throws InterruptedException {
try {
Thread thread1 = new Thread(new MyRunnable());
thread1.start();
} catch (Exception ex) {
System.out.println("Exception:" + ex.getMessage());
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(2 / 1);
System.out.println(2 / 0);
System.out.println(2 / 2);
}
}
thread1的run方法中,有一个2/0
的错误,这属于ArithmeticException
异常,这是一个非检查型异常,因此我们就没用try-catch
代码块包裹住。但是一旦代码抛出了非检查型异常,我们在其它线程里是没办法捕获的。因此,尽管我在主线程里尝试捕获非检查型异常,但是没能捕获到,最终导致程序因为异常不得不终止。
正常情况下,请看:
第二段代码:
package concurrence;
public class Test {
public static void main(String[] args) {
try {
dividByZero();
} catch (Exception ex) {
System.out.println("Exception:" + ex);
}
}
public static void dividByZero() {
System.out.println(2 / 1);
System.out.println(2 / 0);
System.out.println(2 / 2);
}
}
正常情况下,我们可以捕获非检查型异常,使得我们的程序不至于因为异常而终止。
但是现在,在多线程中,我们无法捕获run方法中的非检查型异常。那这难道就意味着我们如果不在run
方法中将非检查型异常用try- catch
代码块将异常catch住,那么程序就会因为异常而终止吗?
当然不是,这时候就可以让UncaughtExceptionHandler
闪亮登场了。
对于可以传播的异常,在线程死亡之前,异常会传递到一个用于处理未捕获异常的处理器。前提是这个处理器必须是一个实现了Thread.UncaughtExceptionHandler
接口的类。
于是,我在MyUncaughtExceptionHandler
类中重写了Thread.UncaughtExceptionHandler
中的uncaughtException
方法,在这个方法中定义了对异常的处理。然后在thread1
start
之前,使用setUncaughtExceptionHandler
方法对该线程进行设置。
第三段代码:
package concurrence;
public class UncaughtExceptionHandlerTest {
public static void main(String[] args) throws InterruptedException {
try {
Thread thread1 = new Thread(new MyRunnable());
thread1.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
thread1.start();
} catch (Exception ex) {
System.out.println("Exception:" + ex.getMessage());
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(2 / 1);
System.out.println(2 / 0);
System.out.println(2 / 2);
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + " " + e.getMessage());
}
}
这样,当run方法中出现了非检查型异常以后,在threa1死亡之前,我们能在主线程中捕获住该异常,使得主程序也能正常结束了,不至于因为异常就终止了。