一、子线程中的异常
- 在主线程中抛出异常会很容易的被发现,因为程序停止继续向下运行了;而在子线程中抛出异常,主线程会继续执行,异常很难被发现。
/**
* 在主线程中抛出异常,程序停止继续运行,会有异常堆栈
* 在子线程中抛出异常,主线程会继续执行,很难发现
*/
public class ThreadExceptions {
public static void main(String[] args) throws InterruptedException {
System.out.println("主线程启动");
Thread thread = new Thread(new Dowork());
thread.start();
Thread.sleep(1000);
System.out.println("主线程继续执行任务");
}
}
class Dowork implements Runnable{
@Override
public void run() {
System.out.println("子线程:"+Thread.currentThread().getName());
throw new RuntimeException();
}
}
- 子线程中的异常无法用传统的方法(try-catch)捕获
因为try-catch只能捕获自己线程中的异常。
/**
* 子线程中的异常无法用传统的方法(try-catch)捕获
*/
public class ThreadExceptions {
public static void main(String[] args) throws InterruptedException {
System.out.println("主线程启动");
try {
Thread thread = new Thread(new Dowork());
thread.start();
}catch (Exception e){
System.out.println("子线程抛出了异常!");
}
Thread.sleep(1000);
System.out.println("主线程继续执行任务");
}
}
class Dowork implements Runnable{
@Override
public void run() {
System.out.println("子线程:"+Thread.currentThread().getName());
throw new RuntimeException();
}
}
- 如果不捕获子线程中的异常,主线程会继续执行,没有人知道发生了异常,会造成意想不到的严重后果。
二、两种捕获子线程异常的解决方案
- 在每个run()方法中编写try-catch(不推荐)
- 使用UncaughtExceptionHandler(推荐)
三、UncaughtExceptionHandler
1.简介
- UncaughExceptionHandler是Thread类提供的一个异常处理器接口,它能检测到线程因为未捕获异常而终止的情况并进行处理。
- UncaughtExceptionHandler异常处理器中的内容很简单,就是调用了uncaughtException()方法。
- 异常处理器的调用策略,看一下uncaughtException()的源码
public void uncaughtException(Thread t, Throwable e) {
// 寻找父线程,调用父线程的uncaughtException(),递归
if (parent != null) {
parent.uncaughtException(t, e);
} else {
// 获取线程的默认的异常处理器:
// 如果没有使用Thread.setDefaultUncaughtExceptionHandler()设置异常处理器,则取不到
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
// 取到了,则执行设置的异常处理器
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
// 没取到,则打印异常信息
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
- 所有,我们需要实现一个自己的异常处理器,并设置给线程,这样当线程中有异常时,就会走我们自己的异常处理器
2.使用我们自己的异常处理器监控线程中的异常
- 自己实现异常处理器
/**
* 自己实现的异常处理器
*/
public class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("线程["+t.getName()+"]异常终止:"+e.getMessage());
}
}
- 使用异常处理器
public class ThreadExceptions {
public static void main(String[] args) {
System.out.println("主线程开始执行...");
Thread.setDefaultUncaughtExceptionHandler(new ThreadExceptionHandler());
Thread thread = new Thread(new DoWorks());
thread.start();
Thread thread1 = new Thread(new DoWorks());
thread1.start();
Thread thread2 = new Thread(new DoWorks());
thread2.start();
System.out.println("主线程继续执行...");
}
}
class DoWorks implements Runnable{
@Override
public void run() {
throw new RuntimeException("数据库连接失败了!");
}
}
- 效果