开发者社区> yexx> 正文

如何捕获java线程中的逃逸的异常

简介: 在java线程中,在run方法中,我们要在run()方法中,把一切的异常有处理掉,也就try-catch掉。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。 线程在run方法抛出异常,没有catch
+关注继续查看

在java线程中,在run方法中,我们要在run()方法中,把一切的异常有处理掉,也就try-catch掉。不能让这个线程抛出异常,因为如果我们不使用特殊的方式的话,我们是无法捕获从这个线程中逃逸的异常的。异常一旦抛出了,那么这个线程就会停止运行,但是不会影响主线程和其它的线程。因为主线程和其它的线程都不知道它抛出了异常。

线程在run方法抛出异常,没有catch

这里写图片描述

那么会有疑问,是不是在main函数里面没有catch

```
package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 测试线程抛异常不能捕获
 * @author yxx
 */
public class ExceptionThread implements Runnable {

    @Override
    public void run() {
        System.out.println("我准备抛出异常,你能接到吗?");
        throw new RuntimeException();
    }
    public static void main(String[] args) {
        try {
            Thread thread = new Thread(new ExceptionThread());
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(thread);
        } catch (Exception e) {
            System.out.println("我要捉住异常");
            e.printStackTrace();
        }
    }
}

这里写图片描述

一样是catch不到的,想想一个线程的抛出异常之后就终止了如果再进行catch,都不在一个线程里面

所以这个时候我们得去实现UncaughtExceptionHandler这个接口来捕获抛出的异常

实现UncaughtExceptionHandler这个接口来捕获抛出的异常

ExceptionThread2.java

package Thread.UncaughtExceptionHandler;

/**
 * 一个抛出异常的线程类 但是想被抓住
 * @author yxx
 */
public class ExceptionThread2 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new RuntimeException();
    }
}

ExceptionThread3.java

package Thread.UncaughtExceptionHandler;

/**
 * 一个抛出异常的线程类 但是想被抓住
 * @author yxx
 */
public class ExceptionThread3 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run by " + t.getName());
        System.out.println("Exception " + t.getUncaughtExceptionHandler());
        throw new NullPointerException();
    }

}

MyUncaughtExceptionHandler.java

package Thread.UncaughtExceptionHandler;

import java.lang.Thread.UncaughtExceptionHandler;

/**
 * 实现UncaughtExceptionHandler接口,抓住抛出的异常
 * @author yxx
 *
 */
public class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caugth: " + e.toString());
    }
}

HandlerThreadFactory.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ThreadFactory;

/**
 * 实现ThreadFactory来创建线程,为每一个thread对象都附上一个未捕获异常的处理器
 * @author yxx
 *
 */
public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this + "creating new thread");
        Thread t = new Thread(r);
        System.out.println("created" + t);
        //为每一个线程设置异常捕获器
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
        return t;
    }
}

CaptureUncaughtException.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 准备创建线程抛出异常,线程外捕获
 * @author yxx
 *
 */
public class CaptureUncaughtException {

    public static void main(String[] args) {
        ExecutorService es = Executors.newCachedThreadPool(new HandlerThreadFactory());
        es.execute(new ExceptionThread2());
        es.execute(new ExceptionThread3());
    }
}

运行截图

这里写图片描述

都能捕获到

如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,并将这个处理器设置为默认的未捕获异常的处理器。

在Thread类中设置一个静态域

SettingDefaultHandler.java

package Thread.UncaughtExceptionHandler;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 如果你知道将要在代码中处处使用相同的异常处理器,那么更加简单的方式是在Thread类中设置一个静态域,
 * 并将这个处理器设置为默认的未捕获异常的处理器。
 * @author yxx
 *
 */
public class SettingDefaultHandler {
    public static void main(String[] args) {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());

        ExecutorService es = Executors.newCachedThreadPool();
        es.execute(new ExceptionThread2());
    }
}

静态域执行效果图

这里写图片描述

说明:这个处理器只有在不存在线程专有的未捕获异常的情况下才会被调用。系统会检查线程的专有的版本,如果没有发现,则检查线程组是有有其专有的uncaughtException()方法。如果也没有,在调用defaultUncaughtExcept。

在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。但是线程依然有可能抛出unchecked exception(如运行时异常),当此类异常跑抛出时,线程就会终结,而对于主线程和其他线程完全不受影响,且完全感知不到某个线程抛出的异常(也是说完全无法catch到这个异常)。JVM的这种设计源自于这样一种理念:线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”“基于这样的设计理念,在Java中,线程方法的异常(无论是checked还是unchecked exception),都应该在线程代码边界之内(run方法内)进行try catch并处理掉.换句话说,我们不能捕获从线程中逃逸的异常。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Java Review - SimpleDateFormat线程不安全原因的源码分析及解决办法
Java Review - SimpleDateFormat线程不安全原因的源码分析及解决办法
15 0
Java 8 - Stream基本实例及Stream的并行处理在线程上的表现
Java 8 - Stream基本实例及Stream的并行处理在线程上的表现
17 0
JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器
JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器
13 0
Java线程基本概念以及创建线程的几种方式
Java线程基本概念以及创建线程的几种方式
12 0
Java的线程
本篇文章介绍了 1. Java的线程生命周期; 2. Java的线程状态切换; 3. Java线程API的使用。
32 0
一个Redis的Java客户端Jedis的学习,线程不安全问题的解决及与MySQL的简单的结合
> Redis 全称 Remote Dictionary Server(即远程字典服务),它是一个基于内存实现的键值型非关系(NoSQL)数据库,由意大利人 Salvatore Sanfilippo 使用 C 语言编写。 > > Redis 遵守 BSD 协议,实现了免费开源,其最新版本是 6.20,常用版本包括 3.0 、4.0、5.0。自 Redis 诞生以来,它以其超高的性能、完美的文档和简洁易懂的源码广受好评,国内外很多大型互联网公司都在使用 Redis,比如腾讯、阿里、Twitter、Github 等等。 简单的来说:Redis是一种极其高效的,迅速的一种基于缓存读写的N
30 0
Java进程和线程
Java进程和线程
14 0
线程是java独有的吗,操作系统本身有没有线程?
线程是java独有的吗,操作系统本身有没有线程?
18 0
Java老掉牙的面试问题:线程交替打印问题,分析实操一下 下
Java老掉牙的面试问题:线程交替打印问题,分析实操一下 下
26 0
+关注
yexx
CSDN博客地址---http://blog.csdn.net/bug_moving GitHub地址---https://github.com/androidwolf
文章
问答
视频
文章排行榜
最热
最新
相关课程
更多
相关电子书
更多
JAVA开发手册1.5.0
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
相关实验场景
更多