使用UncaughtExceptionHandler重启线程
先复习Java中的异常
java.lang.Throwable 顶层父类
|– Error错误:JVM内部的严重问题,如OOM,程序员无法在代码中无法处理。
|–Exception异常:普通的问题。通过合理的处理,程序还可以回到正常执行流程。要求程序员要进行处理。
|–RuntimeException:未检查异常(unchecked exception)。 这类异常是程序员的逻辑问题,由于程序员的疏忽导致的错误(如数组越界,空指针等)。
Java编译器不进行强制要求处理。 也就是说,这类异常在程序中,可以进行处理,也可以不处理。
|–非RuntimeException:已检查异常(checked exception)、编译时异常。这类异常是由一些外部的偶然因素所引起的。Java编译器强制要求处理。也就是说,
程序必须进行对这类异常进行处理,throw,throws或者try catch。
而线程Thread的的run()方法不接受抛出语句,因此对于已检查异常,我们必须进行捕获并处理,如:
@Override
public void run() {
FileInputStream fis = null;
try {
fis = new FileInputStream(new File(""));
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
}
而对于未检查异常,如果在run()方法中运行出现了未检查异常,那么默认的行为是将堆栈跟踪信息写到控制台中(或者记录到错误日志文件中),然后退出程序。
Java为我们提供了一个机制,用来捕获并处理在一个线程对象中抛出的未检查异常,以避免程序终止。用UncaughtExceptionHandler来实现这种机制。
不使用UncaughtExceptionHandler的场景:
public class MyThread implements Runnable {
@Override
public void run() {
Integer.parseInt("yangyongjie");
System.out.println("expect");
}
}
控制台输出:
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "yangyongjie"
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.yang.spbo.other.thread.MyThread.run(MyThread.java:15)
at java.lang.Thread.run(Thread.java:745)
此时,线程立即终止,并没有执行之后的代码输出字符串“expect”。若在执行很重要的代码之前,出现了未检查异常,导致了线程终止,那么就会导致业务异常。
使用UncaughtExceptionHandler后:
首先,自定义异常处理器实现UncaughtExceptionHandler接口,用来捕获和处理运行时出现的未检查异常(RuntimeException)
public class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomUncaughtExceptionHandler.class);
/**
* 可以自定义处理方案,如不断重试、将异常任务存入数据库等
*
* @param t
* @param e
*/
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("An exception has been captured,Thread: {}", t.getId());
LOGGER.error("Exception: {}: {}", e.getClass().getName(), e.getMessage());
LOGGER.error("Thread status: {}", t.getState());
new Thread(new MyThread()).start();
}
}
接着,将异常处理器添加到线程中
public class MyThread implements Runnable {
@Override
public void run() {
// 异常处理器
Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
Integer.parseInt("yangyongjie");
System.out.println("expect");
}
}
再次运行,程序能够持续执行run方法。实际上,如果线程完成了任务,那么它在退出时不会抛出任何异常,从而完成自身生命周期
An exception has been captured
Thread: 10
Exception: java.lang.NumberFormatException: For input string: "yangyongjie"
Stack Trace:
java.lang.NumberFormatException: For input string: "yangyongjie"
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.yang.spbo.other.thread.MyThread.run(MyThread.java:22)
at java.lang.Thread.run(Thread.java:745)
Thread status: RUNNABLE
An exception has been captured
Thread: 12
Exception: java.lang.NumberFormatException: For input string: "yangyongjie"
Stack Trace:
java.lang.NumberFormatException: For input string: "yangyongjie"
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.yang.spbo.other.thread.MyThread.run(MyThread.java:22)
at java.lang.Thread.run(Thread.java:745)
Thread status: RUNNABLE
请注意:UncaughtExceptionHandler可以在无需重启线程的条件下,将日志记录变得更加健壮,因为默认日志在线程执行失败时,不会提供足够的上下文信息。
线程池异常处理,自定义创建线程的工厂,在创建线程时指定
/**
* 创建线程的工厂,指定有意义的线程组名称,方便回溯
*
* @author yangyongjie
* @date 2019/8/14
* @desc
*/
public class CustomThreadFactory implements ThreadFactory {
/**
* 线程池中的线程名称前缀
*/
private String namePrefix; /**
* 用于线程的名称递增排序
*/
private AtomicInteger atomicInteger = new AtomicInteger(1); public CustomThreadFactory(String whatFeaturOfGroup) {
this.namePrefix = "From CustomThreadFactory-" + whatFeaturOfGroup + "-worker-";
} @Override
public Thread newThread(Runnable r) {
String name = namePrefix + atomicInteger.getAndIncrement();
Thread thread = new Thread(r, name);
thread.setUncaughtExceptionHandler(new CustomUncaughtExceptionHandler());
return thread;
}
} /**
* 用来捕获和处理运行时出现的未检查异常(RuntimeException)
* 并重启线程
*
* @author yangyongjie
* @date 2019/11/26
* @desc
*/
public class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomUncaughtExceptionHandler.class); /**
* 可以自定义处理方案,如不断重试、将异常任务存入数据库等
*
* @param t
* @param e
*/
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("uncaughtException:" + e.getMessage(), e);
MDCUtil.removeWithOutContext();
}
}
使用UncaughtExceptionHandler重启线程的更多相关文章
- java UncaughtExceptionHandler 处理线程意外中止
本文转自:http://peirenlei.iteye.com/blog/305079 Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个 ...
- Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程
Java并发-UncaughtExceptionHandler捕获线程异常信息并重新启动线程 一.捕获异常并重新启用线程 public class Testun { public static voi ...
- python通过重启线程,实现服务的热加载
这个思路后来证明不能用于工作. 因为线程调用没有及时返回,所以不能用这种方式来重启服务. 但作为脑洞,也应该作个记录. import os import shutil import datetime ...
- Android Priority Job Queue (Job Manager):线程任务的容错重启机制(二)
Android Priority Job Queue (Job Manager):线程任务的容错重启机制(二) 附录文章4简单介绍了如何启动一个后台线程任务,Android Priority J ...
- .net重启iis线程池和iis站点程序代码【转】
转:http://www.jb51.net/article/44162.htm 重启站点: 复制代码代码如下: /// <summary> /// 根据名字重启站点.(没重 ...
- .net重启iis线程池和iis站点程序代码分享
重启站点: /// <summary> /// 根据名字重启站点.(没重启线程池) /// </summary> /// <param name="sitena ...
- Java线程监听,意外退出线程后自动重启
Java线程监听,意外退出线程后自动重启 某日,天朗气清,回公司,未到9点,刷微博,顿觉问题泛滥,惊恐万分! 前一天写了一个微博爬行程序,主要工作原理就是每隔2分钟爬行一次微博,获取某N个关注朋友微博 ...
- 重启iis线程池和iis站点
服务器监控. 一定时间内或者iis异常,就重启线程池和站点 一般重启站点没啥用.. 重启线程池 效果明显. 重启站点: /// <summary> /// 根据名字重启站点.(没重启线程池 ...
- Android Priority Job Queue (Job Manager):后台线程任务结果传回前台(三)
Android Priority Job Queue (Job Manager):后台线程任务结果传回前台(三) 在附录文章4,5的基础上改造MainActivity.java和MyJob.ja ...
随机推荐
- VS2017中英文切换
离线安装完成, --fix 检查下是否完整 安装时没有勾选的项, 可以下次再补安装 安装时出现缺少*.vsix 如:microsoft.visualstudio.webtoolsextensions. ...
- day35—JavaScript操作元素(创建、删除)
转行学开发,代码100天——2018-04-20 JavaScript对DOM元素的创建.删除操作. 1.创建DOM元素 appendChild方法 createElement(ochild); op ...
- [LeetCode] 287. Find the Duplicate Number(Floyd判圈算法)
传送门 Description Given an array nums containing n + 1 integers where each integer is between 1 and n ...
- Yaconf – 一个高性能的配置管理扩展
鸟哥出品:http://www.laruence.com/2015/06/12/3051.html 首先说说, 这个是干啥的. 我见过很多的项目中, 用PHP文件做配置的, 一个config目录下可能 ...
- openssl使用
一. 加密方法 dsaffdfd fgggg 1.对称加密: 加密算法 + 口令 加密算法: DES(56bits),3DES(用des加密反复加密三次),AES(128bits),Blowfish ...
- [Linux] 027 RPM 包与 源码包的区别
1. 区别 安装之前的区别: 概念上的区别 安装之后的区别: 安装位置不同 2. RPM 包安装位置 安装在默认位置中 RPM 包默认安装路径 明细 /ect 配置文件安装目录 /usr/bin/ 可 ...
- JAVA中JavaBean对象之间属性拷贝的方法
JAVA中JavaBean对象之间的拷贝通常是用get/set方法,但如果你有两个属性相同的JavaBean或有大部分属性相同的JavaBean,对于这种情况,可以采用以下几个简便方法处理. 下面对这 ...
- 次小生成树(Prim + Kruaskal)
问题引入: 我们先来回想一下生成树是如何定义的,生成树就是用n - 1条边将图中的所有n个顶点都连通为一个连通分量,这样的边连成子树称为生成树. 最小生成树很明显就是生成树中权值最小的生成树,那么我们 ...
- 常用的AJAX弹出层代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- kmp(所有长度的前缀与后缀)
http://poj.org/problem?id=2752 Seek the Name, Seek the Fame Time Limit: 2000MS Memory Limit: 65536 ...