Java异常体系图

为什么需要UncaughtExceptionHandler?
首先看一个例子,从0打印到1000,中间子线程抛出异常
public class ExceptionInChildThread implements Runnable {
public static void main(String[] args) {
new Thread(new ExceptionInChildThread()).start();
for (int i=0;i<1000;i++){
System.out.println(i);
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
从结果会发现,抛出的异常基本上被打印的数字埋没了,很难找到。并且,子线程的异常不能通过在外面套用try/catch的方式进行捕获。
捕获线程异常的错误例子(套用try/catch)
public class CantChtchDirectly implements Runnable {
public static void main(String[] args) throws InterruptedException {
try { //try catch针对的是主线程,而异常是发生在子线程中的
new Thread(new CantChtchDirectly(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new CantChtchDirectly(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new CantChtchDirectly(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new CantChtchDirectly(), "MyThread-4").start();
}catch (RuntimeException e){
System.out.println("Caught Exception");
}
}
@Override
public void run() { //这里要在run方法内捕获异常,这时捕获的就是子线程的异常
throw new RuntimeException();
}
}
由于捕获的是主线程的异常,而真正抛出异常的是子线程,因此,并不能真正打印出Caught Exception。
综上所述,为什么需要UncaughtExceptionHandler?
① 主线程可以轻松发现异常,子线程却不行
② 子线程异常无法用传统方法捕获
解决方案一:手动在run方法中添加try/catch(不推荐)
针对上面的问题,我们只要能够捕获出子线程的异常即可,所以只要在子线程中加入try/catch,但是,当有很多的子线程时,就要一个个处理,效率低。
@Override
public void run() { //这里要在run方法内捕获异常,这时捕获的就是子线程的异常
try{
throw new RuntimeException();
}catch (RuntimeException e){
System.out.println("caught exception");
}
}
解决方案二:使用UncaughtExceptionHandler
//创建一个异常处理器,实现Thread.UncaughtExceptionHandler接口
public class MyUncaughtExceptionHanlder implements Thread.UncaughtExceptionHandler{
//设定自己的处理器名字
private String name;
public MyUncaughtExceptionHanlder(String name){
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
//打印到日志
logger.log(Level.WARNING,"线程异常,终止啦"+t.getName(),e);
//输出到控制台
System.out.println(name+"捕获了异常"+t.getName()+" 异常"+e);
}
}
public class UseOwnUncaughtExceptionHandler implements Runnable {
public static void main(String[] args) throws InterruptedException {
//使用异常处理器时,只需要指定异常处理器即可
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHanlder("捕获器1"));
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();
}
@Override
public void run() {
throw new RuntimeException();
}
}
总结

本文探讨了Java中处理线程异常的必要性,因为子线程异常难以被主线程捕获。通过一个实例展示了尝试在主线程捕获异常的错误做法。接着介绍了两种解决方案:1) 手动在每个run方法中添加try/catch块,但这种方式效率低下;2) 使用UncaughtExceptionHandler,这是一个更优雅且推荐的方法,能够集中处理所有未捕获的线程异常。

被折叠的 条评论
为什么被折叠?



