Java多线程探究-线程异常逃逸

线程逃逸

在Thread的run方法中,Java是不允许抛出受检异常的,所以必须由自己捕获,但是对于一些运行时的异常,难免有时候完全捕获到,继而传递到上一层,导致不可预料的程序终止,所以需要在上一层捕获

来看看我们到底不能捕获未受检异常
异常类

class MyRunnable implements Runnable {
    private  int ticket = 10000;
    private Object object;
    @Override
    public void run() {
         System.out.println(3/0);
         System.out.println(3/2);
         System.out.println(4/0);

    }
}

main方法

public class ThreadDemo {

    public static void main(String[] args) {

        try{
            MyRunnable runnable = new MyRunnable();
            Thread t1 = new Thread(runnable, "one");
            Thread t2 = new Thread(runnable, "two");
            Thread t3 = new Thread(runnable, "third");
            Thread t4 = new Thread(runnable, "four");
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }catch (Exception e){
            System.out.println("捕获了");
        }

    }
}

打印结果
这里写图片描述
可以看到,在main方法中,并没有捕获异常,导致异常的逃逸,造成意外的程序中断
UncaughtExceptionHandler
是为了捕获没有被捕获的异常,包括运行时异常,执行错误(内存溢出等),子线程抛出的异常等
每个线程都可以单独设置一个UncaughtExceptionHandler,在线程throw 了运行时异常的时候,异常被传递给未捕获异常处理器UncaughtExceptionHandler是Thread的一个内部接口,我们自定一个Handler

public class ThreadDemo {

    public static void main(String[] args) {

            MyRunnable runnable = new MyRunnable();
            Thread t1 = new Thread(runnable, "one");
            Thread t2 = new Thread(runnable, "two");
            Thread t3 = new Thread(runnable, "third");
            Thread t4 = new Thread(runnable, "four");
            t1.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println("捕获到了");
                }
            });
            t1.start();
            t2.start();
            t3.start();
            t4.start();
    }
}

上面的代码中,t1这个线程的异常就可以会捕获到并处理
也可以设置Thread的默认UncaughtException,使用Thread的静态方法setDefaultUncaughtExceptionHandler,这样所有的线程的抛出的异常都会被处理

MyRunnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable, "one");
Thread t2 = new Thread(runnable, "two");
Thread t3 = new Thread(runnable, "third");
Thread t4 = new Thread(runnable, "four");
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕获到了线程 "+t.getName()+" 异常信息: "+e.getMessage());
    }
});
t1.start();
t2.start();
t3.start();
t4.start();

输出结果,所有线程的异常都被捕获了
这里写图片描述
如果既没有设置单独的异常处理器,也没有设置默认的异常处理器,那么UncaughtException是ThreadGroup的处理器,ThreadGroup类实现了Thread.UncaughtExceptioin接口
ThreadGroup的调用规则
1.如果thread group有父group,那么执行父group的uncaughtException
2.否则如果线程Thread设置了默认的UncaughtExceptoin,那么调用默认的UncaughtExceptoin
3.否则如果异常不是ThreadDeath的实例(ThreadDeath对象是stop方法产生的),就打印出异常栈的信息到System.err流
请看源码
void uncaughtException(Thread t, Throwable e)
calls this method of the parent thread group if there is a parent, or calls the default
handler of the Thread class if there is a default handler, or otherwise prints a stack
trace to the standard error stream. (However, if e is a ThreadDeath object, the stack trace
is suppressed. ThreadDeath objects are generated by the deprecated stopmethod.)

public void uncaughtException(Thread t, Throwable e) {
    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);
        }
    }
}

默认创建的线程都会属于同一个ThreadGroup,线程一个被线程组管理,也可以自定定义其他的线程组
关于ThreadGroup的使用,见我另一篇博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值