【Kill Thread Part.1-7】线程异常处理知多少?

【Kill Thread Part.1-7】线程异常处理知多少?

  • Java异常体系图
  • 实际工作中,如何全局处理异常?为什么要全局处理?不处理行不行?

一、线程未捕获异常UncaughtException应该如何处理?

1、为什么需要UncaughtExceptionHandler?

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

测试代码

/**
 * 描述:  单线程,抛出,处理,有异常堆栈
 * 多线程,子线程如果发生异常,会有什么不同
 */
public class ExceptionInChildThread implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException();
    }

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

image-20220126113220456

子线程运行抛出了异常,但是对于我们主线程而言,运行没有收到丝毫的影响。

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

测试代码

/**
 * 描述:
 * 1.不加 try catch 抛出4个异常,都带线程名字
 * 2.加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
 * 3.执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
 * 说明线程的异常 不能用传统的方法捕获
 */
public class CantCatchDirectly implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws InterruptedException {
        try {
            new Thread(new CantCatchDirectly(),"MyThread-1").start();
            Thread.sleep(300);

            new Thread(new CantCatchDirectly(),"MyThread-2").start();
            Thread.sleep(300);

            new Thread(new CantCatchDirectly(),"MyThread-3").start();
            Thread.sleep(300);

            new Thread(new CantCatchDirectly(),"MyThread-4").start();
        } catch (InterruptedException e) {
            System.out.println("Caught Exception");
        }
    }
}

image-20220126114038077

原因是try/catch只能捕获对应线程类的异常。

③不能直接捕获的后果、提高健壮性

如果不能捕获异常,子线程挂掉了,主线程还在运行,那么业务没人处理了,内部发生了错误。

二、两种解决方案

1、手动在每个run方法里进行try/catch(不推荐)

image-20220126114319748

2、利用UncaughtExceptionHandler(推荐)

  • UncaughtExceptionHandler接口
  • void uncaughtException(Thread t, Throwable e)

异常处理器的调用策略

image-20220126114546997

三、自己实现异常处理器

  • 给程序统一的设置
  • 给每个线程单独设置
  • 给线程池设置

1、自定义的异常处理器

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);
    }

}

2、使用自定义的异常处理器

/**
 * 描述: 使用上面自己写的handler
 */
public class UseOwnUncaughtExceptionHandler implements Runnable{
    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器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();
    }
}

四、常见面试问题

1、Java异常体系

2、如何全局处理异常?为什么要全局处理?不处理行不行?

3、run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?

  • run方法不能上抛异常,只能是进行try/catch处理。
  • 线程会终止运行,打印出堆栈。

4、线程中如何处理某个未处理的异常?

posted @ 2022-01-26 14:37  DarkerG  阅读(51)  评论(0编辑  收藏  举报