处理线程非受控异常


能够帮助管理应用中的错误情况,这是任何编程语言都应具备的重要机制。如同大多数现代编程语言一样,Java语言实现了基于异常的机制来管理错误情况。当检测出错误的时候,Java类会抛出这些异常。也可以使用这些异常或者实现定制化异常来管理程序造成的错误。

Java还提供一种捕获和处理这些异常的机制。方法中必须被捕获或者使用throws语句再次抛出的异常是受检异常,无须指定或捕获的异常称为非受检异常。

  • 受检异常 : 必须在方法的throws语句中指定或内部捕获的异常,例如,IOException 或者 ClassNotFoundException。
  • 非受检异常 : 无须指定或捕获的异常,例如NumberFormatException。

当受检异常在线程对象的run()方法中被抛出来时,由于run()方法不接受throws语句,所以必须捕获和处理这些异常。当非受检异常在线程对象的run()方法中被抛出来时,默认行为是在控制台输出堆栈跟踪,同时退出程序。

不过Java提供了一种机制来捕获和处理线程对象抛出的非受控异常,避免终止程序。

在本节中,通过范例学习这种机制原理。

准备工作

本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。

实现过程

通过如下步骤完成范例:

  1. 首先,实现一个类来处理非受检异常。这个类必须实现UncaughtExceptionHandler接口和接口定义的uncaughtException()方法,此方法依附Thread类。在本范例中,此类命名为ExceptionHandler,然后实现方法记录抛出的Exception和Thread信息。代码如下:

    public class ExceptionHandler implements UncaughtExceptionHandler {
    	@Override
    	public void uncaughtException(Thread t, Throwable e) {
    		System.out.printf("An exception has been captured\n");
    		System.out.printf("Thread: %s\n", t.getId());
    		System.out.printf("Exception: %s: %s\n", e.getClass().getName(), e.getMessage());
    		System.out.printf("Stack Trace: \n");
    		e.printStackTrace(System.out);
    		System.out.printf("Thread status: %s\n", t.getState());
    	}
    }
    
  2. 现在,实现一个类抛出非受检异常。此类命名为Task,指定其实现Runnable接口和run()方法。强制其报错,例如,尝试将字符串转换成整型:

    public class Task implements Runnable {
    	@Override
    	public void run() {
    		int numero = Integer.parseInt("TTT");
    	}
    }
    
  3. 现在实现主类,包含main()方法的Main类:

    public class Main {
    	public static void main(String[] args) {
    
  4. 创建Task对象,以及运行此对象的线程。使用setUncaughtExceptionHandler()设置非受控异常处理器,开始执行线程:

    		Task task = new Task();
    		Thread thread = new Thread(task);
    		thread.setUncaughtExceptionHandler(new ExceptionHandler());
    		thread.start();
    	}
    }
    
  5. 运行程序,查看结果。

工作原理

在下图中显示执行范例输出的结果。通过控制器抛出和捕获的异常记录抛出的Exception和Thread信息,然后输出到控制台上:

pics/01_05.jpg

当线程中被抛出一个异常并且始终未捕获(非受检异常),Java虚拟机检查线程是否有通过匹配方法设置的非捕获异常控制器。如果有,Java虚拟机用Thread对象和Exception参数调用此方法。

如果线程没有非捕获异常处理器,Java虚拟机会在控制台输出堆栈跟踪,并且终止执行已经抛出异常的线程。

扩展学习

Thread类中的静态方法setDefaultUncaughtExcptionHandler()也与非捕获异常处理有关,此方法为应用中的所有线程对象建立一个异常处理器。

当线程中抛出一个非捕获异常时,Java虚拟机寻找异常中三个可能的处理器。

首先是寻找线程对象的非捕获异常处理器,也就是本节中学到的。如果此处理器不存在,Java虚拟机寻找ThreadGroup类中的非捕获异常控制器,这个类在“线程组中分组线程、处理非受控异常”小节中学习。如果此方法也不存在,Java虚拟机会寻找默认的非捕获异常处理器。

如果三种处理器均不存在,Java虚拟器在控制台输出异常的堆栈跟踪,并且终止执行已经抛出异常的线程。

更多关注

  • 本章中“工厂模式创建线程”小节。

猜你喜欢

转载自blog.csdn.net/nicolastsuei/article/details/84502401