Java多线程:7.线程的异常处理

一、子线程中的异常

  • 在主线程中抛出异常会很容易的被发现,因为程序停止继续向下运行了;而在子线程中抛出异常,主线程会继续执行,异常很难被发现。
/**
 * 在主线程中抛出异常,程序停止继续运行,会有异常堆栈
 * 在子线程中抛出异常,主线程会继续执行,很难发现
 */
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("数据库连接失败了!");
    }
}
  • 效果
    在这里插入图片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章