线程的未捕获异常UncaughtException应该如何处理?
为什么需要UncaughtExceptionHandler?
- 主线程可以轻松发现异常,子线程却不行
- 子线程异常无法用传统方法捕获
- 不能直接捕获的后果、提高健壮性
代码演示:
/**
* 1. 不加try catch抛出4个异常,都带线程名字
* 2. 加了try catch,期望捕获到第一个线程的异常,线程234不应该运行,希望看到打印出Caught Exception
* 3. 执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常
* 4. 说明线程的异常不能用传统方法捕获
*/
public class CantCatchDirectly implements Runnable {
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 (RuntimeException e) {
System.out.println("Caught Exception.");
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
两种解决方案
方案一(不推荐):手动在每个run方法里进行try catch
public void run() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println("Caught Exception.");
}
}
方案二(推荐):利用UncaughtExceptionHandler
- UncaughtExceptionHandler接口
- void uncaughtException(Thread t, Throwable e)回调方法
- 异常处理器的调用策略
- 实现方式
- 给程序统一设置
- 给每个线程单独设置
- 给线程池设置
代码演示:实现自己的MyUncaughtExceptionHandler
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());
System.out.println(name + "捕获了异常" + t.getName() + "异常");
}
}
使用刚才自己写的UncaughtExceptionHandler
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();
}
}
打印输出:
十一月 03, 2019 10:43:23 上午 com.hd.thread.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
捕获器1捕获了异常MyThread-1异常
警告: 线程异常,终止啦MyThread-1
捕获器1捕获了异常MyThread-2异常
十一月 03, 2019 10:43:23 上午 com.hd.thread.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-2
捕获器1捕获了异常MyThread-3异常
十一月 03, 2019 10:43:23 上午 com.hd.thread.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-3
捕获器1捕获了异常MyThread-4异常
十一月 03, 2019 10:43:24 上午 com.hd.thread.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止啦MyThread-4
面试问题
1.Java异常体系
网络搜索Java异常体系图。
2.如何全局处理异常?为什么要全局处理?不处理行不行?
实现UncaughtExceptionHandler接口,自定义一个全局处理器。不处理不行,不处理的话程序会抛出异常子线程中断,主线程不影响,会继续运行。
3.run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?
run方法不能够向外抛出异常了,只能try/catch处理,如果run方法里面抛出了RuntimeException,又没有进行处理,那么程序会抛出异常,子线程中断。
4.线程中如何处理某个未处理异常?
同问题2。