Java并发(八)--线程未捕获异常处理详解

1. 为什么需要UncaughtExceptionHandler?

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

/**
 * @author zhoup
 * @date 2020/4/7 14:15
 * @describe
 */
public class ExceptionChildThread implements Runnable{

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

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

在上面代码中,子线程抛出异常,但是主线程却丝毫不受影响。

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

/**
 * @author zhoup
 * @date 2020/4/7 14:20
 * @describe 1. 不加try catch抛出4个异常,都带线程名字
 * 2. 加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
 * 3. 执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
 * 说明线程的异常不能用传统方法捕获
 */
public class ChildeThreadTryCatch implements Runnable{

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

    public static void main(String[] args) {
        try {
            new Thread(new ChildeThreadTryCatch(),"Thread-1").start();
            new Thread(new ChildeThreadTryCatch(),"Thread-2").start();
            new Thread(new ChildeThreadTryCatch(),"Thread-3").start();
            new Thread(new ChildeThreadTryCatch(),"Thread-4").start();
        }catch (RuntimeException e){
            System.out.println("Caught Exception");
        }
    }
}
  • 1.不加try catch抛出4个异常,都带线程名字

    1. 加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
    1. 执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
  • 说明线程的异常不能用传统方法捕获

3. 提高健壮性

2. 两种解决方案

1.直接在run()方法中进行Try Catch操作

缺点:需要在每一个run方法里都进行Try Catch操作,而且可能还不知道抛出的异常类型。

2.使用UncaughtExceptionHandler

源码:

public interface UncaughtExceptionHandler {
        /**
         * Method invoked when the given thread terminates due to the
         * given uncaught exception.
         * <p>Any exception thrown by this method will be ignored by the
         * Java Virtual Machine.
         * @param t the thread
         * @param e the exception
         */
        void uncaughtException(Thread t, Throwable e);
    }

异常处理调用策略:

public void uncaughtException(Thread t, Throwable e) {
    //parent默认也为空
        if (parent != null) {
            parent.uncaughtException(t, e);
        } else {
            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);
            }
        }
    }

自己实现:

/**
 * 描述:     自己的MyUncaughtExceptionHanlder
 */
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());
        System.out.println(name + "捕获了异常" + t.getName() + "异常");
    }
}

/**
 * 描述:     使用刚才自己写的UncaughtExceptionHandler
 */
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();
    }
}

运行结果:
在这里插入图片描述

可以看到,子线程的异常信息通过自己实现的UncaughtExceptionHandler通过日志形式打印出来了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值