7.线程的八大核心基础知识之未捕获异常如何处理

Posted zhihaospace

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7.线程的八大核心基础知识之未捕获异常如何处理相关的知识,希望对你有一定的参考价值。

一.为什么需要UncaughtExceptionHandler

1.主线程可以轻松发现异常,子线程却不行

  • 运行下面程序发现,子线程出现异常会在控制台显示错误信息而不会终止主线程程序,程序依旧运行很难发现错误信息

public class ExceptionInChildThread implements Runnable {
    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new Thread(new ExceptionInChildThread()).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
}

2.子线程异常无法用传统方法捕获

  • 从下面程序可以看出,当第一个线程抛出异常后程序并没有结束继续,直到三个线程都抛出异常并且主程序执行完毕。对于普通异常当捕获到第一个异常后就会异常处理不在继续执行。

  • 这是由于异常发生在每一个线程的run方法中,主线程捕获不到子线程异常

public class CantCatchDirectly implements Runnable {
    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        try {

            new Thread(new CantCatchDirectly(), "thread1").start();
            Thread.sleep(100);
            new Thread(new CantCatchDirectly(), "thread2").start();
            Thread.sleep(100);
            new Thread(new CantCatchDirectly(), "thread3").start();

        } catch (InterruptedException e) {
            System.out.println("捕获到异常");
        }
    }
}

技术图片

3.UncaughtExceptionHandler处理会提高程序的健壮性

二.处理线程异常两种解决方案

1.方案一(不推荐):手动在每一个run方法中进行try/catch处理

2.方案二(推荐):利用UncaughtExceptionHandler接口处理异常

  • UncaughtExceptionHandler接口

  • void uncaughtException(Thread t, Throwable e);

(1)异常处理器的调用策略

  • 如果有父线程的异常处理就调用父线程的

  • 如果没有则判断用户是否自己实现异常处理器,自己实现了就调用自己实现的异常处理器,没有就默认打印堆栈信息

技术图片

 

 (2)自己实现异常处理器

实现方式:

  1. 给程序统一设置

  2. 给线程独立设置

  3. 给线程池设置

自定义异常捕获器:实现 Thread.UncaughtExceptionHandler 接口

import java.util.logging.Level;
import java.util.logging.Logger;

public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

    private String name;

    public MyUncaughtExceptionHandler(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 {
    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));

        new Thread(new CantCatchDirectly(), "thread1").start();
        Thread.sleep(100);

        new Thread(new CantCatchDirectly(), "thread2").start();
        Thread.sleep(100);

        new Thread(new CantCatchDirectly(), "thread3").start();
    }
}

技术图片

 

以上是关于7.线程的八大核心基础知识之未捕获异常如何处理的主要内容,如果未能解决你的问题,请参考以下文章

如何处理尝试捕获异常android

如何处理 Task.Run 异常

swift - 如何处理未捕获的异常

JVM-JVM 是如何处理异常的

如何处理异步函数 UWP App GetFileFromPathAsync(path) 中的异常;

JVM虚拟机-- JVM是如何处理异常的