JAVA并发编程-线程异常

508 阅读2分钟

1、JAVA异常体系图

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

线程的未捕获异常UncaughtExcption应该如何处理

1、为什么需要UncaughtExcptionHandler?

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

主线程往往会打印茫茫多的日志,子线程的异常信息可能埋没在其中没有被发现了,比如这段代码

public class ExceptionInChildThread implements Runnable{

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

    @Override
    public void run() {
        throw new RuntimeException();
    }
}

如果不通过查找去看的话,很容易忽略掉子线程的异常

  • 子线程异常无法用传统方式捕获(try-catch)
/**
 *  1. 不加try catch抛出4个异常,都带线程名字
 *  2. 加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
 * 3. 执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
 *
 * 说明线程的异常不能用传统方法捕获
 */

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

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

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

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

            new Thread(new NotCatchDirectly(), "MyThread-4").start();
            Thread.sleep(300);
        } catch (RuntimeException e) {
            System.out.printf("catch the exception");
        }
    }
}

并没有得到catch到异常,原因是catch只能捕获当前线程中的异常,在main中使用try-catch只会捕获main中产生的异常

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

两种解决方法

1、(不好)手动在每个run方法里面进行try-catch

2、(推荐)利用UncaughtExcptionHandler

  • void uncaughtException(Thread t, Throwable e)
  • 异常处理器的调用策略
  • 自己实现
    • 给程序统一设置;
    • 给每个线程单独设置;
    • 给线程池设置

handler类:

public class OwnExceptionHandler implements Thread.UncaughtExceptionHandler {
    private String name;

    public OwnExceptionHandler(String name) {
        this.name = name;
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        Logger logger = Logger.getAnonymousLogger();
        logger.log(Level.WARNING, "线程异常,终止" + t.getName());
        logger.log(Level.INFO, name + "捕获了异常:" + t.getName() + "异常");
    }
}

使用handler的主类

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

    public static void main(String[] args) throws InterruptedException {
        Thread.setDefaultUncaughtExceptionHandler(new OwnExceptionHandler("自己的捕获器"));

        new Thread(new UseOwnHandler(), "MyThread-1").start();
        Thread.sleep(300);

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

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

        new Thread(new UseOwnHandler(), "MyThread-4").start();
        Thread.sleep(300);
    }
}

结果如下,可以看出handler捕获到了子线程的异常并进行了处理。