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();
}
}
猜你喜欢
- 从远端服务器获取变更数据的主要模式有两种:推(push)和拉(pull)。Push 模式简单来说就是服务端主动将数据变更信息推送给客户端,这
- 1、静态代码块①、格式在java类中(方法中不能存在静态代码块)使用static关键字和{}声明的代码块:public class Code
- 本文实例为大家分享了java实现滑动验证解锁的具体代码,供大家参考,具体内容如下1.html:<div class="dra
- 起因最近在写CRUD的时候,发现有个分页的VO写的健壮性比较差,一时手痒改了一下,没想到改了之后好几个功能都出现了问题。原VO关键代码如下:
- 一:本文使用范围此文不仅仅局限于spring boot,普通的spring工程,甚至是servlet工程,都是一样的,只不过配置一些 * 的
- 在MailSetting里的配置好邮件服务器,然后MailEntity里配置好要发送的邮件主体,最后使用MailServer里的方法Send
- 我们编程的过程中大部分使用了很出色的ORM框架,例如:MyBatis,Hibernate,SpringJDBC,但是这些都离不开数据驱动JD
- 本文实例讲述了Spring实战之方法级别缓存用法。分享给大家供大家参考,具体如下:一 配置文件<?xml version="
- ShardingSphereShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、
- 本文实例讲述了JavaWeb 网上书店 注册和登陆功能。分享给大家供大家参考,具体如下:工具:Eclipse + Navicat源码地址:h
- Write()和WriteLine()都是System.Console提供的方法,两着主要用来将输出流由指定的输出装置(默认为屏幕)显示出来
- 场景做一个消息中心,专门负责发送消息。消息分为几种渠道,包括手机通知(Push)、短信(SMS)、邮件(Email),Websocket等渠
- 一、常见游戏规则从扑克中每次取出4张牌。使用加减乘除,第一个能得出24者为赢。(其中,J代表11,Q代表12,K代表13,A代表1),按照要
- BASE64 编码是一种常用的字符编码,在很多地方都会用到。但base64不是安全领域下的加密解密算法。能起到安全作用的效果很差,而且很容易
- 本文实例分析了C#中结构(struct)的部分初始化和完全初始化,分享给大家供大家参考。具体分析如下:假设有这样一个值类型struct,如下
- 继承和多态派生类具有基类所有非私有数据和行为以及新类自己定义的所有其他数据或行为,即子类具有两个有效类型:子类的类型和它继承的基类的类型。对
- 注册BeanPostProcessorrefresh()调用registerBeanPostProcessors(beanFactory)方
- 我们知道在编程时许多操作(如更新UI)需要在主线程中完成,而且,耗时操作(如网络连接)需要放在子线程中,否则会引起ANR。所以我们常使用Ha
- 如下所示:import java.util.ArrayList;//java中申请不定长度数组public class Test01 {pu
- 首先,这两者是完全不同的概念,绝对不能混为一谈。1.什么是Java内存模型?Java内存模型是Java语言在多线程并 * 况下对于共享变量读写