线程中出现异常的处理

目录

前言

正文

1.线程出现异常的默认行为 

2.使用 setUncaughtExceptionHandler() 方法进行异常处理

3.使用 setDefaultUncaughtExceptionHandler() 方法进行异常处理 

4.线程组内处理异常 

5.线程异常处理的优先性 

总结


前言

在紧密交织的多线程环境中,异常处理是一个经常被讨论的容易被忽视的关键部分。这并不奇怪,因为在编写并发代码时,管理和理解可能出现的各种异常条件可能是一个挑战。在单线程环境中,发生异常时,异常信息会立刻被捕获并处理,然而,在多线程环境中的异常处理复杂性要高很多。未被正确处理的异常可能导致全局性影响,甚至系统崩溃。这给程序稳定性带来威胁,且可能会导致无法预料的行为。因此,对于编写健壮且可靠的并发代码来说,理解并且正确处理线程中的异常是至关重要的。本文旨在深入探讨Java中线程级别的异常处理。我将会详细阐述线程异常的基本概念,错误处理策略以及如何用实际代码进行演示。希望本文能为你在并发编程中如何捕获和处理异常提供有用的参考。


正文

当线程出现异常时,我们可以在该线程 run() 方法的 catch 语句中进行处理。当有多个线程中出现异常时,我们就得在每一个线程 run() 方法得 catch 语句中进行处理,这样回造成代码严重冗余。我们可以使用 setDefaultUncaughtExceptionHandler() 和 setUncaughtExceptionHandler() 方法来集中处理线程的异常。 

1.线程出现异常的默认行为 

创建测试用例

package org.example.Error;public class threadCreateException {static class MyThread extends Thread{@Overridepublic void run() {String username= null;//NUllPointErrorSystem.out.println(username.hashCode());}}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}

运行结果

程序运行后,控制台输出空指针异常。在 Java 的多线程技术中,我们可以对多线程中的异常进行"捕捉"(使用的是 UncaughtExceptionHander 接口),从而对异常进行有效处理。

当线程出现异常而终止时,JVM 虚拟机捕获到此情况,并自动调用 UncaughtExceptionHandler 接口中的 void uncaughtException(Thread t,Throwable e) 方法来处理异常,使对多个线程的异常处理更加集中。

2.使用 setUncaughtExceptionHandler() 方法进行异常处理

新建测试用例

package org.example.Error;
import java.lang.Thread.UncaughtExceptionHandler;
public class Main {static class MyThread extends Thread{@Overridepublic void run() {String username= null;//NUllPointErrorSystem.out.println(username.hashCode());}}public static void main(String[] args) throws InterruptedException {MyThread t1 = new MyThread();t1.setName(" 线程     t1");t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("线程:"+t.getName()+" 出现了异常:");e.printStackTrace();}});t1.start();MyThread t2 = new MyThread();t2.setName(" 线程 t2");Thread.sleep(10);t2.start();}}

程序运行结果如图

setUncaughtExceptionHandler() 方法的作用是对指定的线程对象设置默认的异常处理器,在 Thread 类中,我们还可以使用 setDefaultUncaughtExceptionHandler() 方法对所有线程对象设置异常处理器。

3.使用 setDefaultUncaughtExceptionHandler() 方法进行异常处理 

新建测试用例 

package org.example.Error;public class Main3 {static class MyThread extends Thread{@Overridepublic void run() {String username= null;//NUllPointErrorSystem.out.println(username.hashCode());}}public static void main(String[] args) {MyThread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("线程:"+t.getName()+" 出现了异常:");e.printStackTrace();}});MyThread t1 = new MyThread();t1.setName(" 线程t1 ");t1.start();MyThread t2 = new MyThread();t2.setName(" 线程t2 ");t2.start();}
}

运行结果如下

4.线程组内处理异常 

线程的异常处理情况我们已经了解,那么线程组内的异常处理情况又是怎么样的呢? 

package org.example.Error;public class thread_Group1 {static class MyThread extends Thread {private String num;public MyThread(ThreadGroup group, String name, String num) {super(group, name);this.num = num;}@Overridepublic void run() {int numInt = Integer.parseInt(num);while (true) {System.out.println("死循环中: " + Thread.currentThread().getName());}}}public static void main(String[] args) {ThreadGroup group = new ThreadGroup("我得线程组");MyThread[] myThreads = new MyThread[10];for (int i = 0; i < myThreads.length; i++) {myThreads[i] = new MyThread(group,"线程 "+(i+1),"1");myThreads[i].start();}MyThread newT = new MyThread(group,"报错线程 ","a");newT.start();}
}

运行结果如图:

从运行结果来看,默认的情况下线程组中的一个线程出现异常后不会影响其他线程的运行。

如何实现线程组内一个线程出现异常后全部线程都停止呢?

class MyThreadGroup extends ThreadGroup {public MyThreadGroup(String name) {super(name);}@Overridepublic void uncaughtException(Thread t, Throwable e) {super.uncaughtException(t, e);this.interrupt();}}

注意,使用 this 关键字停止线程 。this 代表的是线程组!

public void uncaughtException(Thread t, Throwable e)  方法的 t 参数是出现异常的线程对象。

类 MyThread.java 的代码如下: 

    static class MyThread extends Thread {private String num;public MyThread(ThreadGroup group, String name, String num) {super(group, name);this.num = num;}@Overridepublic void run() {int numInt = Integer.parseInt(num);while (true) {if (!this.isInterrupted()){System.out.println("死循环中: " + Thread.currentThread().getName());}}}}

需要注意的是,使用自定义 java.lang.ThreadGroup 线程组,并重写 uncaughtException() 方法处理组内线程中断行为时,每个线程对象中的 run() 方法内部不要有异常 catch 语句。如果有 catch 语句 ,public void uncaughtException(Thread t, Throwable e) 方法不执行。

main 方法如下:

 public static void main(String[] args) throws InterruptedException {MyThreadGroup group = new MyThreadGroup("我的线程组");MyThread[] myThreads = new MyThread[10];for (int i = 0; i < myThreads.length; i++) {myThreads[i] = new MyThread(group," 线程 "+(i+1),"1");myThreads[i].start();}MyThread newT = new MyThread(group,"报错线程","a");newT.start();}

运行后一个线程出现异常,其他线程全部停止,运行结果如图:

5.线程异常处理的优先性 

前面介绍了若干个线程异常处理方式,这些方式如果一起运行,会出现什么运行结果呢? 

创建测试用例: 


public class threadExceptionMove {//线程类static class MyThread extends Thread{private String num = "a";public MyThread() {}public MyThread(ThreadGroup group, String name) {super(group, name);}@Overridepublic void run() {int numInt = Integer.parseInt(num);System.out.println(" 在线程中打印: "+(numInt+1));}}//线程组的异常处理static class MyThreadGroup extends ThreadGroup{public MyThreadGroup(String name) {super(name);}@Overridepublic void uncaughtException(Thread t, Throwable e) {super.uncaughtException(t, e);System.out.println("线程组的异常处理");e.printStackTrace();}}//对象的异常处理static class ObjectUncaughtExceptionHandler implements UncaughtExceptionHandler{@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println(" 对象的异常处理 ");e.printStackTrace();}}//静态的异常处理static class StateUncaughtExceptionHandler implements UncaughtExceptionHandler{@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("静态的异常处理");e.printStackTrace();}}
}

创建运行类 Run1:

    static class Run1{public static void main(String[] args) {MyThread myThread = new MyThread();//对象myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());//类MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());myThread.start();}}

运行结果如图:

更改 Run1:

static class Run1{public static void main(String[] args) {MyThread myThread = new MyThread();//对象//smyThread//.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());//类MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());myThread.start();}}

运行结果如图:

再继续实验,创建 Run2

static class Run2 {public static void main(String[] args) {MyThreadGroup myThreadGroup = new MyThreadGroup("我的线程组");MyThread myThread = new MyThread(myThreadGroup, "我的线程");//对象myThread.setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());//类MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());myThread.start();}}

运行结果如图:

更改 Run2:

static class Run2 {public static void main(String[] args) {MyThreadGroup myThreadGroup = new MyThreadGroup("我的线程组");MyThread myThread = new MyThread(myThreadGroup, "我的线程");//对象//myThread//        .setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());//类MyThread.setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());myThread.start();}}

运行结果如图:

本示例想要打印 "静态的异常处理" 信息,必须在  public void uncaughtException(Thread t, Throwable e) 方法中加上 super.uncaughtException(t, e); 代码。这是因为 super.uncaughtException(t, e); 方法中会调用 Thread.getDefaultUncaughtExceptionHandler();来执行 设置的静态方法。源代码如下:

    //super.uncaughtException(t, e);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);}}}

继续更改 Run2 代码

static class Run2 {public static void main(String[] args) {MyThreadGroup myThreadGroup = new MyThreadGroup("我的线程组");MyThread myThread = new MyThread(myThreadGroup, "我的线程");//对象//myThread//        .setUncaughtExceptionHandler(new ObjectUncaughtExceptionHandler());//类//MyThread.//        setDefaultUncaughtExceptionHandler(new StateUncaughtExceptionHandler());myThread.start();}}

运行结果如图:

最终得出结论就是如果调用 setUncaughtExceptionHandler() 方法,则其设置的异常处理器优先运行,其他异常处理器不运行。


总结

当线程出现异常时,如果该异常没有被捕获和处理,线程就会终止。正确处理线程中的异常是保证程序健壮性和稳定性的关键所在。

处理线程中的异常通常有两种方式:一种是使用 try-catch 块捕获异常,第二种是使用线程的未捕获异常处理器(UncaughtExceptionHandler)来处理未捕获的异常。

在使用 try-catch 块捕获异常时,我们可以通过捕获并处理异常来保证程序的稳定性,应该将 catch 块放置在可能出现异常的代码块之后,防止程序因未处理的异常而崩溃。在捕获到异常后,可以在 catch 块中采取相应的措施,比如记录日志或者返回默认值等。

而在使用线程的未捕获异常处理器时,我们需要通过实现 UncaughtExceptionHandler 接口,并将其设置到对应线程上,当线程发生未捕获异常时,处理器中的 uncaughtException 方法会被回调在该方法中,我们可以采取相应的措施来处理异常,比如记录日志或者发送警报等。

当出现异常时,如何选择捕获和处理异常的方式取决于具体情况,但处理异常的目标总是相同的,即保障程序能够继续稳定执行。因此,对于线程中的异常,我们需要充分了解其出现的原因和可能的影响,制定相应的处理策略,并积极监控和记录程序运行时的异常情况。

总之,对线程中出现的异常进行正确处理是保证程序健壮性和稳定性的重要措施,有助于保证程序顺利运行并最大限度地避免非预期的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/194916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决:ValueError: binary mode doesn‘t take an encoding argument

解决&#xff1a;ValueError: binary mode doesn‘t take an encoding argument 文章目录 解决&#xff1a;ValueError: binary mode doesn‘t take an encoding argument背景报错问题报错翻译报错位置代码报错原因解决方法方法一方法二今天的分享就到此结束了 背景 在使用之前…

USART的PAL库编程

USART驱动的工作原理 总结一下我们之前使用中断的方式来进行数据的发送和接收 如果收到数据数据在RDR寄存器中 RXNE标志位就从0到1触发中断 进入中断服务函数 把数据缓存在队列中 然后在到进程函数中断接收数据函数中进行出队处理 发送数据就是把中断关闭&#xff08;标志位TXE…

日志模块Loguru

安装 Loguru 仅支持 Python 3.5 及以上的版本&#xff0c;使用 pip 安装即可&#xff1a; pip install loguru开箱即用 Loguru 的主要概念是只有一个&#xff1a;logger from loguru import loggerlogger.info("This is log info!") logger.warning("This i…

食物相关的深度学习数据集合集—食物、饮料、肉类、餐具等数据集

最近收集了一大波与食物酒水相关的数据集&#xff0c;包含食物、饮料、肉类、餐具等不同等类型的数据集&#xff0c;废话不多说&#xff0c;给大家逐一介绍&#xff01;&#xff01; 1、自制啤酒配方数据库 超过20万自制啤酒配方数据库&#xff0c;数据集包含不同精酿啤酒的名…

Docker Image(镜像)——5

目录&#xff1a; Docker 镜像是什么镜像生活案例镜像分层生活案例为什么需要镜像镜像命令详解 镜像命令清单docker imagesdocker tagdocker pulldocker pushdocker rmidocker savedocker loaddocker historydocker importdocker image prunedocker build镜像操作案例 查找镜像…

etlbox.3.1.0 for NET 轻量级 ETL数据集成库 Crack

适用于 .NET 的轻量级 ETL&#xff08;提取、转换、加载&#xff09;工具箱和数据集成库 高度可定制 厌倦了使用几乎不可能实现复杂需求的用户界面&#xff1f;使用 ETLBox&#xff0c;可以轻松编写适合您独特需求的代码。插入您自己的逻辑或修改现有行为以满足您的特定要求。 …

ScyllaDB 基础入门

简介 ScyllaDB 是一种开源的 NoSQL 数据库&#xff0c;它提供了高性能、低延迟的数据处理能力&#xff0c;同时保持了与 Apache Cassandra 高度的兼容性。ScyllaDB 使用了一种名为 “Seastar” 的高效并行编程框架&#xff0c;并采用了 C 进行开发&#xff0c;因此它能够充分利…

基于ssm Vue的戒烟网站源码和论文

基于ssm Vue的戒烟网站源码和论文734 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 环境&#xff1a; jdk8 tomcat8.5 开发技术 ssm 摘要 随着互联网的高速发展&#xff0c;线上管理成为当代人们管理事物的重要手段之一&#xff…

numpy知识库:基于numpy绘制灰度直方图

前言 对于灰度图像而言&#xff0c;灰度直方图可以统计灰度图像内各个灰度级出现的次数。 灰度直方图的横坐标是灰度图像中各像素点的灰度级。灰度的数值范围为[0, 255]。因此&#xff0c;如果将图像分为256个灰度级&#xff0c;那么每个灰度级唯一对应一个灰度&#xff1b;如…

流媒体方案之Nginx——实现物联网视频监控项目

目录 前言 一、Nginx是什么 二、Nginx在流媒体方案中的位置​编辑 三、软硬件准备 四、移植编译Nginx 五、运行Ngnix 六、测试流媒体方案 七、浏览器播放 前言 最近想做一个安防相关的项目&#xff0c;所以跟着韦东山老师的视频来学习视频监控方案的相关知识&#xff0…

lv11 嵌入式开发 ADC 16

目录 1 ADC 简介 2 Exynos4412下的ADC控制器 2.1 总览 2.2 特征 2.3 ADC转换时间 2.4 IO口 ​编辑3 ADC寄存器详解 3.1 寄存器介绍 3.2 ADCCON控制寄存器 3.3 ADCDAT 3.4 CLRINTADC 3.5 ADCMUX ​编辑 4 ADC编程 1 ADC 简介 ADC(Analog to Digital Converter)即…

Android开发,JNI开发项目创建

文章目录 Android开发&#xff0c;JNI开发项目创建1.jni是什么 Android开发&#xff0c;JNI开发项目创建 创建工程 1.jni是什么 使得java可以访问底层c语言&#xff0c;java本地化接口&#xff0c;是桥梁。 运行下我们的项目 出现这个就是我们的JNI开发环境已经配置好了 是…

【SpringBoot】SpringBoot配置Swagger

文章目录 前言配置步骤使用步骤总结 前言 使用Swagger只需要按照规范去定义接口及接口的相关信息&#xff0c;就可以做到生成接口文档和在线接口调试页面 官网&#xff1a;Swagger官网 Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案 配置步骤 1.导入knife4j的m…

shell命令编写

1. 1 #!/bin/bash 2 3 directory_path"/txh"4 5 # 使用 find 命令查找指定路径下的文件&#xff0c;并使用 wc 命令统计行数&#xff08;即文件个数&#xff09;6 7 file_count$(find "directory_path" -type f | wc -l)8 9 10 echo "在路径$director…

网工学习5 交换机端口相关配置

交换机的接口属性默认支待一般网络环境&#xff0c;一般情况下是不需要对其接口进行设置的。在某些情况下需 要对其端口属性进行配置时&#xff0c;配置的对象主要有接口隔离、速率、双工等信息。 5.1 接口隔离设置 > 配置接口 GE0/0/1 和 GE0/0/2 的接口隔离功能&#xf…

Leetcode1094. 拼车

Every day a Leetcode 题目来源&#xff1a;1094. 拼车 解法1&#xff1a;差分数组 对于本题&#xff0c;设 a[i] 表示车行驶到位置 i 时车上的人数。我们需要判断是否所有 a[i] 都不超过 capacity。 trips[i] 相当于把 a 中下标从 fromi 到 toi−1 的数都增加 numPassenge…

【ArcGIS Pro微课1000例】0045:深度学习--车牌模糊

借助ArcGIS Pro提供的车牌模糊训练模型,可以很方便实现车牌模糊。 文章目录 一、车牌模糊对比二、工具介绍三、案例实现一、车牌模糊对比 车牌模糊前: 车牌模糊后: 二、工具介绍 本功能使用的依然是ArcGIS Pro提供的深度学习工具中的使用深度学习分类像素(Classify Pixel…

JavaScript基础知识20——循环结构:退出循环

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 最近一段时间没学习JavaScript&#xff0c;今天看数字孪生的资料&#xff0c;发现很多低代码开发还是得必须熟悉JavaScript才行&#xff0c;为了以后方便搞数字孪生&#xff0c;有时间还是继续学习下JavaScript。 以下…

如何开启Windows Server 2016 远端桌面

使用GUI 设定 服务器管理器–> 本地服务器–> 远端桌面 启用远端桌面 远端–> 允许远端连线至此电脑 会提示防火墙设定跟电源设定 防火墙之前已经关闭了 完成

matlab 多目标粒子群优化算法MOPSO

1、内容简介 略 21-可以交流、咨询、答疑 多目标、粒子群 2、内容说明 多目标粒子群优化算法MOPSO 3、仿真分析 略 %% Problem Definition TestProblem3; % Set to 1, 2, or 3 switch TestProblem case 1 CostFunction(x) MyCost1(x); nVar5; …