Java并发编程示例(八):处理线程的非受检异常

作者:junjie 时间:2022-03-23 14:15:57 

Java语言中,把异常分为两类:

受检异常: 这类异常必须在throws子句中被显式抛出或者在方法内被捕获。例如,IOException异常或ClassNotFoundException异常。
非受检异常: 这类异常不需要显式抛出或捕获。例如,NumberFormatException异常。

当一个受检异常在Thread对象的run()方法中被抛出时,我们必须捕获并处理它,因为run()方法不能抛出异常。而一个非受检异常在Thread对象的run()方法中被抛出时,默认的行为是在控制台打印出堆栈跟踪信息然后退出程序。

幸运的是,Java为我们提供了一种机制,专门用于处理由Thread对象抛出的非受检异常,以避免程序的退出。

在本节,我们用示例来演示这种机制。

知其然

按照下面所示步骤来实现我们的示例。

1.首先,我们需要实现一个用于处理非受检异常的类。这个类必须实现UncaughtExceptionHandler类,实现在该接口中声明的uncaughtException()方法。在本例中,该类名为ExceptionHandler,uncaughtException()方法将异常以及抛出异常的线程信息打印出来。代码如下:


public class ExceptionHandler implements Thread.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("diguage.com");
    }
}

3.创建程序的主类,Main类,然后实现main()方法。代码如下:


public class Main {
    public static void main(String[] args) {


4.创建Task对象,并且创建一个Thread对象来执行之。使用setUncaughtExceptionHandler() 方法设置非受检异常的处理类。然后,启动线程。代码如下:


Task task = new Task();
Thread thread = new Thread(task);
thread.setUncaughtExceptionHandler(new ExceptionHandler());
thread.start();

5.运行示例,查看结果。

知其所以然

从下面的输出片段可以看出异常执行的结果。异常被抛出,然后被处理类捕获并将异常信息打印到了控制台。


An exception has been captured
Thread: 9
Exception: java.lang.NumberFormatException: For input string: "diguage.com"
Stack Trace:
java.lang.NumberFormatException: For input string: "diguage.com"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at com.diguage.books.concurrencycookbook.chapter1.recipe8.Task.run(Task.java:13)
    at java.lang.Thread.run(Thread.java:722)
Thread status: RUNNABLE

Process finished with exit code 0

当一个线程抛出一个异常,并且该异常(这里特指非受检异常)没有捕获时,Java虚拟机会检查是否通过相应方法设置非受检异常处理类,如果以已经设置过,则调用uncaughtException()方法,并将线程和异常作为参数传递给方法。

如果没有设置处理类,Java虚拟机就会在控制台将堆栈跟踪信息打印出来,然后退出程序。

永无止境

Thread类还有一个和非受检异常处理相关的方法。这就是静态方法setDefaultUncaughtExceptionHandler(),该方法可以设置程序中所有线程的非受检异常的处理类。

当线程中抛出一个未捕获的异常时,Java虚拟机会从三个地方寻找异常处理类:

首先,从线程对象中查找异常处理类,这就是我们本节所学内容。如不存在,则从线程所在的线程组(ThreadGroup)中查找异常处理类。关于这部分内容,以后会专门讲解。如果还是不存在,则查找上面刚刚提到的程序默认异常处理类。

如果上面提到的异常处理都不存在,则Java虚拟机将异常的堆栈跟踪信息打印到控制台,然后退出程序。

拿来主义

本文是从 《Java 7 Concurrency Cookbook》 (D瓜哥窃译为 《Java7并发示例集》 )翻译而来,仅作为学习资料使用。没有授权,不得用于任何商业行为。

小有所成

ExceptionHandler类的完整代码


package com.diguage.books.concurrencycookbook.chapter1.recipe8;

/**
 * 非受检异常处理类
 * Date: 2013-09-22
 * Time: 23:11
 */
public class ExceptionHandler implements Thread.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());
    }
}

Task类的完整代码


package com.diguage.books.concurrencycookbook.chapter1.recipe8;

/**
 * 异常生成类
 * Date: 2013-09-22
 * Time: 23:18
 */
public class Task implements Runnable {
    @Override
    public void run() {
        int numero = Integer.parseInt("diguage.com");
    }
}

Main类的完整代码


package com.diguage.books.concurrencycookbook.chapter1.recipe8;

/**
 * 示例的主类
 * Date: 2013-09-22
 * Time: 23:20
 */
public class Main {
    public static void main(String[] args) {
        Task task = new Task();
        Thread thread = new Thread(task);
        thread.setUncaughtExceptionHandler(new ExceptionHandler());
        thread.start();
    }
}

标签:Java,并发编程,非受检异常
0
投稿

猜你喜欢

  • C#实现类型的比较示例详解

    2022-02-18 18:17:44
  • Java中Mybatis-Plus使用方式介绍

    2021-11-14 05:49:56
  • Android View与Compose互相调用实例探究

    2021-06-11 09:07:29
  • Java求最小生成树的两种算法详解

    2023-11-10 07:21:24
  • Android超实用的Toast提示框优化分享

    2022-12-20 08:36:32
  • C#实现生成所有不重复的组合功能示例

    2023-04-18 15:49:43
  • android之BroadcastReceiver应用详解

    2021-08-31 16:05:21
  • C++实现LeetCode(205.同构字符串)

    2023-06-21 04:06:54
  • java实现哈弗曼编码与反编码实例分享(哈弗曼算法)

    2023-11-25 04:54:05
  • java 集合----Map、Collection

    2022-11-09 03:39:01
  • java合并多个文件的实例代码

    2023-07-28 12:56:02
  • 两种用空格分隔的java字符串的方式

    2023-10-01 05:51:04
  • Winform让DataGridView左侧显示图片

    2021-09-24 03:50:38
  • 浅谈Java线程Thread之interrupt中断解析

    2023-07-19 09:25:11
  • Java实战在线选课系统的实现流程

    2022-12-19 10:34:30
  • java web服务器实现跨域访问

    2023-09-17 06:55:08
  • C#的File类实现文件操作实例详解

    2022-08-03 14:33:44
  • Java实现的断点续传功能的示例代码

    2023-05-25 12:17:22
  • Java多线程 ThreadLocal原理解析

    2022-11-15 12:48:50
  • C++多重继承二义性原理实例解析

    2021-10-08 20:18:33
  • asp之家 软件编程 m.aspxhome.com