Java thread中对异常的处理策略

InterruptedException异常处理方式 InterruptedException异常处理方式 一、上抛 二、响应中断或恢复中断 1. 响应中断 2. 恢复中断 3. 最佳实践 阅读详情

前言

    想讨论这个话题有一段时间了。记得几年前的时候去面试,有人就问过我一个类似的问题。就是java thread中对于异常的处理情况。由于java thread本身牵涉到并发、锁等相关的问题已经够复杂了。再加上异常处理这些东西,使得它更加特殊。 概括起来,不外乎是三个主要的问题。1. 在java启动的线程里可以抛出异常吗? 2. 在启动的线程里可以捕捉异常吗? 3. 如果可以捕捉异常,对于checked exception和unchecked exception,他们分别有什么的处理方式呢?

     现在, 我们就一个个的来讨论。

线程里抛出异常

    我们可以尝试一下在线程里抛异常。按照我们的理解,假定我们要在某个方法里抛异常,需要在该定义的方法头也加上声明。那么一个最简单的方式可能如下:

Java代码  收藏代码
  1. public class Task implements Runnable {  
  2.   
  3.     @Override  
  4.     public void run() throws Exception {  
  5.         int number0 = Integer.parseInt("1");  
  6.         throw new Exception("Just for test");  
  7.     }  
  8. }  

    可是,如果我们去编译上面这段代码,会发现根本就编译不过去的。系统报的错误是:

Java代码  收藏代码
  1. Task.java:3: error: run() in Task cannot implement run() in Runnable  
  2.     public void run() throws Exception {  
  3.                 ^  
  4.   overridden method does not throw Exception  
  5. 1 error  

     由此我们发现这种方式行不通。也就是说,在线程里直接抛异常是不行的。可是,这又会引出一个问题,如果我们在线程代码里头确实是产生了异常,那该怎么办呢?比如说,我们通过一个线程访问一些文件或者对网络进行IO操作,结果产生了异常。或者说访问某些资源的时候系统崩溃了。这样的场景是确实可能会发生的,我们就需要针对这些情况进行进一步的讨论。

异常处理的几种方式

     在前面提到的几种在线程访问资源产生了异常的情况。我们可以看,比如说我们访问文件系统的时候,会抛出IOException, FileNotFoundException等异常。我们在访问的代码里实际上是需要采用两种方式来处理的。一种是在使用改资源的方法头增加throws IOException, FileNotFoundException等异常的修饰。还有一种是直接在这部分的代码块增加try/catch部分。由前面我们的讨论已经发现,在方法声明加throws Exception的方式是行不通的。那么就只有使用try/catch这么一种方式了。

    另外,我们也知道,在异常的处理上,一般异常可以分为checked exception和unchecked exception。作为unchecked exception,他们通常是指一些比较严重的系统错误或者系统设计错误,比如Error, OutOfMemoryError或者系统直接就崩溃了。对于这种异常发生的时候,我们一般是无能为力也没法恢复的。那么这种情况的发生,我们会怎么来处理呢?

checked exception

     在线程里面处理checked exception,按照我们以前的理解,我们是可以直接捕捉它来处理的。在一些thread的示例里我们也见过。比如说下面的一部分代码:

Java代码  收藏代码
  1. import java.util.Date;  
  2. import java.util.concurrent.TimeUnit;  
  3.   
  4. public class FileLock implements Runnable {  
  5.     @Override  
  6.     public void run() {  
  7.         for(int i = 0; i < 10; i++) {  
  8.             System.out.printf("%s\n", new Date());  
  9.             try {  
  10.                 TimeUnit.SECONDS.sleep(1);  
  11.             } catch(InterruptedException e) {  
  12.                 System.out.printf("The FileClock has been interrupted");  
  13.             }  
  14.         }  
  15.     }  
  16. }  

     我们定义了一个线程执行代码,并且在这里因为调用TimeUnit.SECONDS.sleep()方法而需要捕捉异常。因为这个方法本身就会抛出InterruptedException,我们必须要用try/catch块来处理。

     我们启动该线程并和它交互的代码如下:

Java代码  收藏代码
  1. import java.util.concurrent.TimeUnit;  
  2.   
  3. public class Main {  
  4.     public static void main(String[] args) {  
  5.         // Creates a FileClock runnable object and a Thread  
  6.         // to run it  
  7.         FileClock clock=new FileClock();  
  8.         Thread thread=new Thread(clock);  
  9.           
  10.         // Starts the Thread  
  11.         thread.start();  
  12.         try {  
  13.             // Waits five seconds  
  14.             TimeUnit.SECONDS.sleep(5);  
  15.         } catch (InterruptedException e) {  
  16.             e.printStackTrace();  
  17.         };  
  18.         // Interrupts the Thread  
  19.         thread.interrupt();  
  20.     }  
  21. }  

     这部分的代码是启动FileLock线程并尝试去中断它。我们可以发现在运行的时候FileLock里面执行的代码能够正常的处理异常。

    因此,在thread里面,如果要处理checked exception,简单的一个try/catch块就可以了。

unchecked exception

     对于这种unchecked exception,相对来说就会不一样一点。实际上,在Thread的定义里有一个实例方法:setUncaughtExceptionHandler(UncaughtExceptionHandler). 这个方法可以用来处理一些unchecked exception。那么,这种情况的场景是如何的呢?

    setUncaughtExceptionHandler()方法相当于一个事件注册的入口。在jdk里面,该方法的定义如下:

Java代码  收藏代码
  1. public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {  
  2.     checkAccess();  
  3.     uncaughtExceptionHandler = eh;  
  4. }  

     而UncaughtExceptionHandler则是一个接口,它的声明如下:

Java代码  收藏代码
  1. public interface UncaughtExceptionHandler {  
  2.     /** 
  3.      * Method invoked when the given thread terminates due to the 
  4.      * given uncaught exception. 
  5.      * <p>Any exception thrown by this method will be ignored by the 
  6.      * Java Virtual Machine. 
  7.      * @param t the thread 
  8.      * @param e the exception 
  9.     */  
  10.     void uncaughtException(Thread t, Throwable e);  
  11. }  

     在异常发生的时候,我们传入的UncaughtExceptionHandler参数的uncaughtException方法会被调用。

     综合前面的讨论,我们这边要实现handle unchecked exception的方法的具体步骤可以总结如下:

1. 定义一个类实现UncaughtExceptionHandler接口。在实现的方法里包含对异常处理的逻辑和步骤。

2. 定义线程执行结构和逻辑。这一步和普通线程定义一样。

3. 在创建和执行改子线程的方法里在thread.start()语句前增加一个thread.setUncaughtExceptionHandler语句来实现处理逻辑的注册。

    下面,我们就按照这里定义的步骤来实现一个示例:

    首先是实现UncaughtExceptionHandler接口部分:

Java代码  收藏代码
  1. import java.lang.Thread.UncaughtExceptionHandler;  
  2.   
  3. public class ExceptionHandler implements UncaughtExceptionHandler {  
  4.     public void uncaughtException(Thread t, Throwable e) {  
  5.         System.out.printf("An exception has been captured\n");  
  6.         System.out.printf("Thread: %s\n", t.getId());  
  7.         System.out.printf("Exception: %s: %s\n",   
  8.                 e.getClass().getName(), e.getMessage());  
  9.         System.out.printf("Stack Trace: \n");  
  10.         e.printStackTrace(System.out);  
  11.         System.out.printf("Thread status: %s\n", t.getState());  
  12.     }  
  13. }  

     这里我们添加的异常处理逻辑很简单,只是把线程的信息和异常信息都打印出来。

    然后,我们定义线程的内容,这里,我们故意让该线程产生一个unchecked exception:

Java代码  收藏代码
  1. public class Task implements Runnable {  
  2.   
  3.     @Override  
  4.     public void run() {  
  5.         int number0 = Integer.parseInt("TTT");  
  6.     }  
  7. }  

     从这代码里我们可以看到,Integer.parseInt()里面的参数是错误的,肯定会抛出一个异常来。

    现在,我们再把创建线程和注册处理逻辑的部分补上来:

Java代码  收藏代码
  1. public class Main {  
  2.     public static void main(String[] args) {  
  3.         Task task = new Task();  
  4.         Thread thread = new Thread(task);  
  5.         thread.setUncaughtExceptionHandler(new ExceptionHandler());  
  6.         thread.start();  
  7.     }  
  8. }  

     现在我们去执行整个程序,会发现有如下的结果:

Java代码  收藏代码
  1. An exception has been captured  
  2. Thread: 8  
  3. Exception: java.lang.NumberFormatException: For input string: "TTT"  
  4. Stack Trace:   
  5. java.lang.NumberFormatException: For input string: "TTT"  
  6.     at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)  
  7.     at java.lang.Integer.parseInt(Integer.java:492)  
  8.     at java.lang.Integer.parseInt(Integer.java:527)  
  9.     at Task.run(Task.java:5)  
  10.     at java.lang.Thread.run(Thread.java:722)  
  11. Thread status: RUNNABLE  

    这部分的输出正好就是我们前面实现UncaughtExceptionHandler接口的定义。

    因此,对于unchecked exception,我们也可以采用类似事件注册的机制做一定程度的处理。

总结

     Java thread里面关于异常的部分比较奇特。你不能直接在一个线程里去抛出异常。一般在线程里碰到checked exception,推荐的做法是采用try/catch块来处理。而对于unchecked exception,比较合理的方式是注册一个实现UncaughtExceptionHandler接口的对象实例来处理。这些细节的东西如果没有碰到过确实很难回答。


原文: http://shmilyaw-hotmail-com.iteye.com/blog/1881302

SkillClaw:让大模型 Agent skill在多用户生态中实现群体进化的框架 随着大模型应用步入深水区,基于 LLM 的智能体(Agent)正从单一的“沙盒玩具”转变为处理真实世界复杂任务的生产力工具。然而,现有的 Agent 系统通常面临一个致命瓶颈——部署即固化。为了解决这一问题,最近有一篇新论文**《SkillClaw: Let Skills Evolve Collectively with Agentic Evolver》**提出了一种多用户生态 Agent 群体进化框架。 阅读详情

相关推荐

opencv读取海康威视摄像头相关配置

1、开发环境 海康威视的网络摄像头使用: 开发工具:vs2015 C++ 海康SDK 2、相关操作 下载海康威视SDK:网址:http://www.hikvision.com/cn/download_61.html • 1:对照自己的开发平台可以下载设备网络SDK_Win32设备网络SDK_Win64,解压到本地文件下: • 2:VS配置 、Opencv配置。参考址 http://blog.youkuaiyun.com/poem_qianmo/article/details/19809337 (建议自己创

HMJ115的博客 984

Thread setUncaughtExceptionHandler

setUncaughtExceptionHandler 用于获取线程运行时异常 线程在执行时是不能抛出 checked 异常的,IDE 只会提示你用 try-catch 包裹起来。因此主线程无法直接获取子线程的线程信息,而每个 Thread 可以通过 setUncaughtExceptionHandler 注册一个回调接口 setUncaughtExceptionHandler public cl...

旧时光 | YoungChen's 博客 1953

数据结构之栈(Stack)的实现详解

堆栈是一种线性数据结构,其插入新元素和删除现有元素都发生在堆栈的顶部。栈(Stack)按照"后进先出"(Last-In-First-Out,LIFO)的原则存储和访问数据。栈类似于现实生活中的堆叠物体,比如一摞书或者一堆盘子。

swadian2008的博客 3812

java thread 异常_Java Thread异常的处理方式

run()方法不允许throw exception,因此所有的异常必须在run()方法内进行处理。方式一:使用try-catchpackage study.thread.exceptiontest;/**** 使用try-catch处理线程异常**/public class ExceptionHandle1 implements Runnable {@Overridepublic void run...

weixin_32827773的博客 1971

二次开发vba_CATIA VBA(VBS)二次开发:使用Search批量选择元素

在CATIA二次开发中很多在程序中进行自动交互的方法或函数都需要使用选择集作为参数,将几何元素按照要求批量添加到选择集中也是实现程序自动运行的有效方法。在前面的文章《CATIA使用VBA(VBS)二次开发时用户的交互选择》和《CATIA使用VBA(VBS)二次开发时工程图和草图位置的交互选择函数Indicate2D》中介绍了在CATIA VBA(VBS)二次开发中用户和选择集之间的交互操...

weixin_32497403的博客 1321

基于航天宏图PIE-SAR软件的高分三号(GF-3)SAR影像的预处理

软件官网 航天宏图—国内领先的卫星运营与应用服务提供商(官网) 一、数据导入 数据导入-GF-3-根据模式选择 参数文件导入解压后GF-3数据的XML文件 通道自动填充 设置输出目录 确定 等待,加载图像、自动构建金字塔 二、复数数据转换 强度/幅度特征是SAR影像最主要的特征之一,基于SAR强度/幅度影像可以提取地物目标信息,因此需要将SAR复数数据转换为SAR强度/幅度数据。导入输入影像,设置参数类型,输出目录、命名、类型; 漫长的等待 三、多视 为提...

weixin_52127098的博客 9003

java thread 异常_Java thread中对异常的处理策略

转载:http://shmilyaw-hotmail-com.iteye.com/blog/1881302前言想讨论这个话题有一段时间了。记得几年前的时候去面试,有人就问过我一个类似的问题。就是java thread中对于异常的处理情况。由于java thread本身牵涉到并发、锁等相关的问题已经够复杂了。再加上异常处理这些东西,使得它更加特殊。 概括起来,不外乎是三个主要的问题。1. 在java...

weixin_39539563的博客 639

无人机正射影像DOM孔洞修补的另一种方法并调整影像色差(附GlobalMapper24安装包(中文注册版))

之前介绍了用GlobalMapper联合PhotoShop对无人机正射影像DOM进行破洞修补,但是ps修图非常耗时,需要耐心和足够的细心。对于大面积的水域空洞,纹理特征都差不多,没必要修补得那么细致入微,本文介绍另一种直接在Global Mapper中快速修补大面积水域空洞的方法。 一、Global Mapper中检查数据 二、使用“数字化”工具,绘制需要补洞的多边形区域 三、导出绘制好的矢量区域 四、打开影像下载软件,选择影像图源 五、下载影像 六、调整影像的色差 七、合并影像并输出 八、检查结果数据

从地图看世界的专栏 1548

用Thread中的UncaughtExceptionHandler来处理未捕获的异常

为什么80%的码农都做不了架构师?>>> ...

weixin_34237596的博客 776

python全栈入门到实战【基础篇 03】入门实操:第一个Python程序 + PyCharm使用 + 输入输出全解析

本文是一篇Python入门教程,主要介绍PyCharm编辑器的安装配置和基础使用,以及Python输入输出语法的实操练习。文章分为四个部分:1)PyCharm的下载安装与基础配置;2)第一个Python程序"Hello World"的编写与运行;3)Python输入输出函数print()和input()的详细讲解;4)个人信息录入系统的实战案例。教程包含大量截图和动图演示,适合Python新手跟随操作,快速掌握编辑器使用和基础语法。

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 4018

玩转Docker小游戏项目系列: Docker部署红心纸牌网页小游戏

玩转Docker小游戏项目系列: Docker部署红心纸牌网页小游戏

jks212454的博客 420

Java多线程编程中的异常处理策略

在Java中,异常处理通常涉及到这个结构。这在单线程程序中已经很常见了,但在多线程环境下,使用它就需要更多的考量。比如,咱们要考虑异常是否应该在当前线程内部处理,还是需要传递给其他线程或者主线程来处理。除了基本的异常捕获机制,多线程环境中还有一个重要的概念:线程间的异常传递。在多线程程序中,一个线程抛出的异常通常不会影响其他线程。但有时候,咱们可能需要将一个线程的异常通知给其他线程,或者需要主线程知道子线程的异常情况。这就涉及到了线程间的通信和协调。那么,怎么做到这一点呢?小黑这就给大家展示一下。

宋小黑的博客 1797

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java多线程之Thread类

本文讲述了Java多线程中Thread类创建线程的方法,线程的状态和线程的常见属性与方法,以及对应执行之后线程的状态如何改变

2501_90345090的博客 992

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java多线程中的异常处理

在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。但是线程依然有可能抛出unchecked exception,当此类异常跑抛出时,线程就会终结,而对

kiyoki的专栏 465

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

JDK源码那些事儿之浅析Thread上篇

JAVA中多线程的操作对于初学者而言是比较难理解的,其实联想到底层操作系统时我们可能会稍微明白些,对于程序而言最终都是硬件上运行二进制指令,然而,这些又太过底层,今天来看一下JAVA中的线程,浅析JDK源码中的Thread类,之后能帮助我们更好的处理线程问题 前言 JDK版本号:1.8.0_171 在Thread注释中可以看到大佬对其进行的解释: Thread就是...

java梦工厂 203

Exception、Thread(线程)

1、Exception (1)throw 关键字,自定义抛出异常的内容 package com.itheima.demo01Exception; /* throw关键字:作用:在指定的方法中抛出指定的异常 使用格式:throw new xxxException("异常产生的原因"); 注意事项: 1.throw关键字必须写在方法的内部 2.throw关键字后边new的对象必须是Exception或者Exception的子类对象 3.throw关键字抛出指定的异常对象,我们就必

于小猿的博客 920

线程池中线程抛了异常,该如何处理?

点击上方“芋道源码”,选择“设为星标”管她前浪,还是后浪?能浪的浪,才是好浪!每天 10:33更新文章,每天掉亿点点头发...源码精品专栏原创 | Java 2021超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 RocketMQ 源码解析数据库中间件 Sharding-JDBC 和 MyCAT 源码解析作业调度中间件 E...

芋艿V 178

Java多线程中的异常处理

在java多线程程序中,所有线程都不允许抛出未捕获的checked exception,也就是说各个线程需要自己把自己的checked exception处理掉。这一点是通过java.lang.Runnable.run()方法声明(因为此方法声明上没有throw exception部分)进行了约束。但是线程依然有可能抛出unchecked exception,当此类异常跑抛出时,线程就...

weixin_30469895的博客 69

Android 全局异常上报

开始实现 1、实现Thread.UncaughtExceptionHandler接口 public class ExceptionHelper implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { ...

Misolamiso的博客 861

菜鸡学习day16_异常

菜鸡学习day16 异常没太懂,过段时间有空看书,书看完第四章了,囫囵吞枣 package day16; import java.io.FileNotFoundException; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java....

ViVi_Z的博客 183
上一篇: 乐视秒杀:每秒十万笔交易的数据架构解读
下一篇: Java中byte相加的问题.
兵哥笑而不语
博客等级 码龄25年 3粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值