一、为什么需要Thread.UncaughtExceptionHandler
1.主线程可以轻松找到异常,但是子线程不行。
/**
* 子线程异常问题
*
* @author xuehw
* @date 2020-03-05
*/
public class ExceptionInChildThread implements Runnable {
public static void main(String[] args) {
new Thread(new ExceptionInChildThread()).start();
for (int i = 0; i < 2000; i++) {
System.out.println(i);
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
运行过后我们发现似乎没有任何异常
但是往上查找,我们发现了异常堆栈信息,这样显然是不行的,子线程出错,不及时处理,会导致程序出现问题。
2.子线程无法用传统方式捕获。
/**
* try..catch无法捕获
*
* @author xuehw
* @date 2020-03-05
*/
public class CantCatchExp implements Runnable{
public static void main(String[] args) throws InterruptedException {
try {
new Thread(new CantCatchExp(), "Thread-1").start();
Thread.sleep(300);
new Thread(new CantCatchExp(), "Thread-2").start();
Thread.sleep(300);
new Thread(new CantCatchExp(), "Thread-3").start();
Thread.sleep(300);
new Thread(new CantCatchExp(), "Thread-4").start();
} catch (RuntimeException e) {
System.out.println("GET EXCEPTION.11111");
}
}
@Override
public void run() {
throw new RuntimeException();
}
}
上面例子可以看出,在主线程中进行try…catch并没有捕获到子线程中抛出的异常,没有执行catch中的语句。
二、怎么使用Thread.UncaughtExceptionHandler
关于上面子线程异常主线程捕获问题,有两种解决方案。
第一种我们可以在子线程中手动进行try…catch,这种不是特别推荐。
另外一种就是利用Thread.UncaughtExceptionHandler。
1.源码分析
上面是UncaughtExceptionHandler及他调用的uncaughtException方法源码。
2.如何实现
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* UncaughtExceptionHandler
*
* @author xuehw
* @date 2020-03-05
*/
public class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler {
private String name;
public ThreadExceptionHandler(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
*
* @author xuehw
* @date 2020-03-05
*/
public class UseExpHandler implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread.setDefaultUncaughtExceptionHandler(new ThreadExceptionHandler("异常捕获器-001"));
new Thread(new UseExpHandler(), "Thread-1").start();
Thread.sleep(200);
new Thread(new UseExpHandler(), "Thread-2").start();
Thread.sleep(200);
new Thread(new UseExpHandler(), "Thread-3").start();
Thread.sleep(200);
new Thread(new UseExpHandler(), "Thread-4").start();
}
@Override
public void run() {
throw new RuntimeException();
}
}
运行结果: