线程中出现异常的处理
目录
前言
正文
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
方法会被回调。在该方法中,我们可以采取相应的措施来处理异常,比如记录日志或者发送警报等。当出现异常时,如何选择捕获和处理异常的方式取决于具体情况,但处理异常的目标总是相同的,即保障程序能够继续稳定执行。因此,对于线程中的异常,我们需要充分了解其出现的原因和可能的影响,制定相应的处理策略,并积极监控和记录程序运行时的异常情况。
总之,对线程中出现的异常进行正确处理是保证程序健壮性和稳定性的重要措施,有助于保证程序顺利运行并最大限度地避免非预期的错误。
相关文章:
线程中出现异常的处理
目录 前言 正文 1.线程出现异常的默认行为 2.使用 setUncaughtExceptionHandler() 方法进行异常处理 3.使用 setDefaultUncaughtExceptionHandler() 方法进行异常处理 4.线程组内处理异常 5.线程异常处理的优先性 总结 前言 在紧密交织的多线程环境中,异…...
点击元素以外的事件监听
在项目中,我们经常会遇到需要监听目标元素以外的区域被点击或鼠标移入移出等需求。 例如下面我们有一个表格里面嵌套表单的组件 我希望点击n行的时候,n行的元素变成表单元素进行输入或者选择, 当我点击其他其他区域n行又会恢复成数据展示…...
猫头虎分享ubuntu20.04下VSCode无法输入中文解决方法
🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…...
tcpdump使用心得
参考原文 https://danielmiessler.com/p/tcpdump/ 几个用例 tcpdump -i eth0 显示eth0网卡当前所有的抓包情况eth0是网卡名,可以通过ifconfig获得,也可以通过 tcpdump -D 显示当前可以监听的网卡 -i 参数表示接口,后跟要监听的网卡 tcpdu…...
QJsonObject 是 Qt 框架中用于表示 JSON 对象的类
QJsonObject 是 Qt 框架中用于表示 JSON 对象的类。 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于在不同平台和语言之间传输和存储数据。QJsonObject 类提供了一种方便的方式来创建、解析和操作 JSON 对象。 以下是…...
kafka3.6.0部署
部署zk https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.9.1/apache-zookeeper-3.9.1.tar.gz tar -xf apache-zookeeper-3.9.1.tar.gz -C /apps cd /apps/ && ln -s apache-zookeeper-3.9.1 zookeeper 修改配置bash grep -vE ^$|^# conf/zo…...
MybatisPlus批量插入(伪批量),增强为真实批量插入
项目基于优秀开源项目:若依 项目背景:项目中牵扯到数据批量导入,为提高性能,先考虑将MybatisPlus伪批量插入增强为真实批量插入 MybatisPlus源码: MybatisPlus支持批量插入,但是跟踪源码发现底层是将批量…...
【零基础入门Python】Python If Else流程控制
✍面向读者:所有人 ✍所属专栏:零基础入门Pythonhttps://blog.csdn.net/arthas777/category_12455877.html Python if语句 Python if语句的流程图 Python if语句示例 Python If-Else Statement Python if else语句的流程图 使用Python if-else语句 …...
新手零基础学习彩铅画,彩铅快速入门教程合集
一、教程描述 画画是很美好的一件事情,你可以把你想到的,或者看到的都画下来,照相机可以拍下任何你看到的,但是你想到的任何事物,只能通过绘画的方式来表达。本套教程是非常不错的,彩铅的小视频教程&#…...
线程池的拒绝策略
文章目录 线程池的拒绝策略AbortPolicy拒绝策略:CallerRunsPolicy拒绝策略:DiscardOldestPolicy拒绝策略:DiscardPolicy拒绝策略: 线程池的拒绝策略 若在线程池当中的核心线程数已被用完且阻塞队列已排满,则此时线程池…...
Redis7--基础篇5(管道、发布订阅)
管道是什么 管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列,先进先出特性就保证数据的…...
Unity中Shader指令优化(编译后指令解析)
文章目录 前言一、我们先创建一个简单的Shader二、编译这个Shader,并且打开1、编译后注意事项2、编译平台 和 编译指令数3、顶点着色器用到的信息4、顶点着色器计算的核心部分5、片元着色器用到的信息6、片元着色器核心部分 前言 我们先读懂Shader编译后代码&#…...
单个 Zip 文件体积超过 40GB
单个 Zip 文件体积超过 40GB WinRAR 平时用的多,不过有时候为了更好的通用性,也常常用到 zip 格式.查了一下资料,说是 zip 单个文件的体积不能超过 4GB. 自己动手试了下,用 WinRAR 创建出来的 zip 文件,大小可以超过 40GB, 如下图 为了压缩速度快,压缩方式用的是 “存储” Wi…...
pandas 基础操作3
数据删减 虽然我们可以通过数据选择方法从一个完整的数据集中拿到我们需要的数据,但有的时候直接删除不需要的数据更加简单直接。Pandas 中,以 .drop 开头的方法都与数据删减有关。 DataFrame.drop 可以直接去掉数据集中指定的列和行。一般在使用时&am…...
开发知识点-Maven包管理工具
Maven包管理工具 SpringBootSpringSecuritydubbo图书电商后台实战-环境设置(JDK8, STS, Maven, Spring IO, Springboot)点餐小程序Java版本的选择和maven仓库的配置视频管理系统&&使用maven-tomcat7插件运行web工程SpringTool suite——maven项目…...
104. 二叉树的最大深度
104. 二叉树的最大深度 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right…...
JAVA毕业设计113—基于Java+Springboot+Vue的体育馆预约系统(源代码+数据库+12000字论文)
基于JavaSpringbootVue的体育馆预约系统(源代码数据库12000字论文)113 一、系统介绍 本项目前后端分离,本系统分为管理员、用户两种角色 用户角色包含以下功能: 注册、登录、场地(查看/预订/收藏/退订)、在线论坛、公告查看、我的预订管理、我的收藏…...
【自动化测试】pytest 用例执行中print日志实时输出
author: jwensh date: 20231130 pycharm 中 pytest 用例执行中 print 日志 standout 实时命令行输出 使用场景 在进行 websocket 接口进行测试的时候,希望有一个 case 是一直执行并接受接口返回的数据 def on_message(ws, message):message json.loads(message)…...
【深度学习】KMeans中自动K值的确认方法
1 前言 聚类常用于数据探索或挖掘前期,在没有做先验经验的背景下做的探索性分析,也适用于样本量较大情况下的数据预处理等方面工作。例如针对企业整体用户特征,在未得到相关知识或经验之前先根据数据本身特点进行用户分群,然后再…...
github问题解决(持续更新中)
1、ssh: connect to host github.com port 22: Connection refused 从.ssh文件夹中新建文件名为config,内容为: Host github.com Hostname ssh.github.com Port 4432、解决 git 多用户提交切换问题 使用系统命令ssh创建rsa公私秘钥 C:\Users\fyp01&g…...
如何创建一个vue工程
1.打开vue安装网址:安装 | Vue CLI (vuejs.org) 2.创建一个项目文件夹 3.复制地址 4.打开cmd,进入这个地址 5.复制粘贴vue网页的安装命令 npm install -g vue/cli 6.创建vue工程 vue create vue这里可以通过上下键来进行选择。选最后一个选项按回车。 …...
50 代码审计-PHP无框架项目SQL注入挖掘技巧
目录 演示案例:简易SQL注入代码段分析挖掘思路QQ业务图标点亮系统挖掘-数据库监控追踪74CMS人才招聘系统挖掘-2次注入应用功能(自带转义)苹果CMS影视建站系统挖掘-数据库监控追踪(自带过滤) 技巧分析:总结: demo段指的是代码段,先…...
基于Spring、SpringMVC、MyBatis的企业博客网站
文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于Spring、SpringMVC、MyBatis的企业博…...
spring日志输出到elasticsearch
1.maven <!--日志elasticsearch--><dependency><groupId>com.agido</groupId><artifactId>logback-elasticsearch-appender</artifactId><version>3.0.8</version></dependency><dependency><groupId>net.l…...
谷歌 Gemini 模型发布计划推迟:无法可靠处理部分非英语沟通
本心、输入输出、结果 文章目录 谷歌 Gemini 模型发布计划推迟:无法可靠处理部分非英语沟通前言由谷歌 CEO 桑达尔・皮查伊做出决策从一开始,Gemini 的目标就是多模态、高效集成工具、API花有重开日,人无再少年实践是检验真理的唯一标准 谷歌…...
Ubuntu显卡及内核更新问题
显卡安装(2023.12.04) # 查看显卡型号 lspci | grep -i nvidia # 卸载原nvidia 显卡驱动 sudo apt-get --purge remove nvidia*# 禁用nouveau(nouveau是ubuntu自带显卡驱动) sudo gedit /etc/modprobe.d/blacklist.conf # 新增2行…...
SpringBoot错误处理机制解析
SpringBoot错误处理----源码解析 文章目录 1、默认机制2、使用ExceptionHandler标识一个方法,处理用Controller标注的该类发生的指定错误1).局部错误处理部分源码2).测试 3、 创建一个全局错误处理类集中处理错误,使用Controller…...
牛客剑指offer刷题模拟篇
文章目录 顺时针打印矩阵题目思路代码实现 扑克牌顺子题目思路代码实现 把字符串转换成整数题目思路代码实现 表示数值的字符串题目思路代码实现 顺时针打印矩阵 题目 描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如…...
Locust单机多核压测,以及主从节点的数据通信处理!
一、背景 这还是2个月前做的一次接口性能测试,关于locust脚本的单机多核运行,以及主从节点之间的数据通信。 先简单交代下背景,在APP上线之前,需要对登录接口进行性能测试。经过评估,我还是优先选择了locust来进行脚…...
ERROR: [pool www] please specify user and group other than root
根据提供的日志信息,PHP-FPM 服务未能启动的原因是配置文件中的一个错误。错误消息明确指出了问题所在: [29-Nov-2023 14:28:26] ERROR: [pool www] please specify user and group other than root [29-Nov-2023 14:28:26] ERROR: FPM initialization …...
用ps做网站画布一般建多大/百度搜索引擎优化公司哪家强
1、ADB万能驱动 https://pan.baidu.com/s/1oS2ekR1isEHVgu2eMe9n6w 2、安卓手机屏幕共享 https://pan.baidu.com/s/1P_VnzKBigAKMV0DBqbY2gw 3、IOS手机屏幕共享 http://pan.baidu.com/s/1boHL5nh转载于:https://www.cnblogs.com/xiaoxitest/p/6132761.html...
流放之路做装备词缀网站/郑州做网站推广
源码下载 Dubbo Dubbo学习 问题:如果通过nginx实现前台调用后台的业务逻辑,.那么如果后台的服务器需要做新增/删除时必须手动的修改nginx配置文件. Nginx主要的作用就是反向代理. 微服务的治理方案 说明:如果增加服务器或者减少服务器都是自动完成 业务逻辑说明: 当服务的…...
网站优化布局/sem推广竞价托管
点击上方,选择星标或置顶,每天给你送干货!阅读大概需要12分钟跟随小博主,每天进步一丢丢张皓:南京大学计算机系机器学习与数据挖掘所(LAMDA)硕士生,研究方向为计算机视觉和机器学习,特别是视觉识…...
新泰市住房和城乡建设局网站/广州seo网络推广员
2019独角兽企业重金招聘Python工程师标准>>> Error Boundaryrender方法新增返回类型Portals支持自定义DOM属性setState传入null时不会再触发更新更好的服务器端渲染新的打包策略...1. 使用Error Boundary处理错误组件 之前,一旦某个组件发生错误…...
毕业设计做网站的步骤/广州网站排名优化报价
本节书摘来自异步社区《Android 应用案例开发大全(第二版)》一书中的第1章,第1.4节 DDMS的灵活应用 ,作者 吴亚峰 , 于复兴 , 杜化美,更多章节内容可以访问云栖社区“异步社区”公众号查看 1.4 DDMS的灵活应用Android …...
猎场第几集做的网站推广/推广方案怎么做
1. 找样本文章好辛苦啊,都没有批量下载,要一篇一篇下载,找到一个630多篇英语小说的网站,现在还有160多篇没下载。但没有办法了,要研究必须先要有样本数据。 2. 终于解出了a^logb(n) <> n^logb(a)的转换方式。 转…...