ThreadGroup的异常
UncaughtExceptinoHandler
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
int x = 1 / 0;
}
};
Thread thd = new Thread(r);
thd.start();
}
复制代码
默认主线程创建了一个尝试除0而故意抛出ArithmeticException对象的runnable
按照下面的方式编译清单
javac ExceptionThread.java
运行程序
java ExceptionThread
你会看到类ArithmeticException的实例抛出的一条异常栈信息:
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
at ExceptionThread$1.run(ExceptionThread.java)
at java.lang.Thread.run(Thread.java:745)
复制代码
一旦run()方法抛出异常,线程就会中止并被下列活动取代:
- java虚拟机(JVM)寻找Thread.UncaughtExceptionHandler的实例,该实例有Thread的void set UncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法设置。当找到这个handler时,线程就会执行他的void uncaughtException(Thread t, Throwable e)方法,这里t代表了抛出异常线程所关联的Thread对象,而e代表了被抛出的异常或者错误本身--可能会抛出一个java.lang.OutOfMemoryError对象,如果uncaughtException()抛出了一个异常或错误,这个异常或者错误会被JVM忽略。
- 假设setUncaughtExceptionHandler()未经过调用,JVM就会把控制权给线程关联的ThreadGroup对象上的uncaughtException(Thread t, Throwable e)方法。假设这个ThreadGroup没被继承且uncaughtException方法没有被重写,那么此时若其父ThreadGroup存在,uncaughtException()又会把控制权移交给其父ThreadGroup的uncaughtException()方法。否则,就检查默认的未捕获异常处理器是否已经被设置(通过Thread的static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExcetpionHandler handler)方法)。如果默认未捕获异常处理器已经被设置过,其uncaughtException方法就会被传入相同的两个参数进行调用。反之,uncaughtException()方法检查其Throwable参数是否为java.lang.ThreadDeath的实例。如果是,就没什么特别的了。否则就像清单4-1中异常消息显示的那样,一条包含了线程名称和错误栈的消息就被打印到标准错误流中,线程名称返回子该线程的getname()方法,错误栈出自Throwable栈的printStackTrace()的方法。
清单4-2演示了Thread的setUncaughtExceptionHandler()和setDefaultcaughtExceptionHandler()方法。
清单4-2 未捕获异常处理器示例
public class ExceptinoThread {
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
int x = 1 / 0;
}
};
Thread thd = new Thread(r);
Thread.UncaughtExceptionHandler uceh;
uceh = new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Caught throwable" + e + "for thread" + t);
}
};
thd.setUncaughtExceptionHandler(uceh);
uceh = new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Default uncaught exception handler");
System.out.println("Caught throwable" + e + "for thread" + t);
}
};
thd.setDefaultUncaughtExceptionHandler(uceh);
thd.start();
}
}
复制代码
编译清单4-2(javac ExceptionThread.java),并运行最终程序(java ExceptionThread)。你应该能观测到这样的输出:
Caught throwablejava.lang.ArithmeticException: / by zerofor threadThread[Thread-0,5,main]
复制代码
因为默认的处理器并未调用,你看不到它的输出。想要看到那样的输出,你必须注释掉thd.setUncaughtExceptionHandler(uceh);这行。如果你也注释掉了thd.setDefaultUncaughtExceptionHandler(uceh);这行,那么你就会看到原本清单4-1中的输出。