【Kill Thread Part.1-7】线程异常处理知多少?
【Kill Thread Part.1-7】线程异常处理知多少?
- Java异常体系图
- 实际工作中,如何全局处理异常?为什么要全局处理?不处理行不行?
一、线程未捕获异常UncaughtException应该如何处理?
1、为什么需要UncaughtExceptionHandler?
①主线程可以轻松发现异常,子线程却不行
测试代码
/**
* 描述: 单线程,抛出,处理,有异常堆栈
* 多线程,子线程如果发生异常,会有什么不同
*/
public class ExceptionInChildThread implements Runnable{
@Override
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) {
Thread thread = new Thread(new ExceptionInChildThread());
thread.start();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
子线程运行抛出了异常,但是对于我们主线程而言,运行没有收到丝毫的影响。
②子线程异常无法用传统方法捕获
测试代码
/**
* 描述:
* 1.不加 try catch 抛出4个异常,都带线程名字
* 2.加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
* 3.执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
* 说明线程的异常 不能用传统的方法捕获
*/
public class CantCatchDirectly implements Runnable{
@Override
public void run() {
throw new RuntimeException();
}
public static void main(String[] args) throws InterruptedException {
try {
new Thread(new CantCatchDirectly(),"MyThread-1").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"MyThread-2").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"MyThread-3").start();
Thread.sleep(300);
new Thread(new CantCatchDirectly(),"MyThread-4").start();
} catch (InterruptedException e) {
System.out.println("Caught Exception");
}
}
}
原因是try/catch只能捕获对应线程类的异常。
③不能直接捕获的后果、提高健壮性
如果不能捕获异常,子线程挂掉了,主线程还在运行,那么业务没人处理了,内部发生了错误。
二、两种解决方案
1、手动在每个run方法里进行try/catch(不推荐)
2、利用UncaughtExceptionHandler(推荐)
- UncaughtExceptionHandler接口
- void uncaughtException(Thread t, Throwable e)
异常处理器的调用策略
三、自己实现异常处理器
- 给程序统一的设置
- 给每个线程单独设置
- 给线程池设置
1、自定义的异常处理器
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 描述:自己的未处理异常处理器
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private String name;
public MyUncaughtExceptionHandler(String name) {
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.WARNING, t.getName() + "线程异常!终止了!", e);
System.out.println(name + "捕获了异常" + t.getName() + "异常" + e);
}
}
2、使用自定义的异常处理器
/**
* 描述: 使用上面自己写的handler
*/
public class UseOwnUncaughtExceptionHandler implements Runnable{
public static void main(String[] args) throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new UseOwnUncaughtExceptionHandler(), "MyThread-4").start();
}
@Override
public void run() {
throw new RuntimeException();
}
}
四、常见面试问题
1、Java异常体系
2、如何全局处理异常?为什么要全局处理?不处理行不行?
3、run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?
- run方法不能上抛异常,只能是进行try/catch处理。
- 线程会终止运行,打印出堆栈。