- 线程的未捕获异常UncaughtException应该如何处理?
1、为什么需要UncaughtExceptionHandler?
- 主线程可以轻松发现异常,子线程却不行
- 子线程异常无法用传统方法(try-catch)捕获(类似main方法中执行thread.start,抛出异常是在子线程的run中,而try-catch的是主线程main,所以捕获不到)
- 不能直接捕获会导致一些后果(无法捕获到异常,做相应的重试操作逻辑)
2、两种解决方案
方案一(不推荐):手动在每个run方法里进行try catch
public class CanCatchDirectly implements Runnable{
public static void main(String[] args) throws InterruptedException {
new Thread(new CanCatchDirectly(), "MyThread-1").start();
Thread.sleep(300);
new Thread(new CanCatchDirectly(), "MyThread-2").start();
Thread.sleep(300);
new Thread(new CanCatchDirectly(), "MyThread-3").start();
Thread.sleep(300);
new Thread(new CanCatchDirectly(), "MyThread-4").start();
}
@Override
public void run() {
try {
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.println("Caught Exception");
}
}
}
//输出结果
Caught Exception
Caught Exception
Caught Exception
Caught Exception
方案二(推荐):利用UncaughtExceptionHandler
(1)UncaughtExceptionHandler接口
(2)void uncaughtException(Thread t, Throwable e);
Thread.java
————————
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
————————
(3)异常处理器的调用策略
(4)自己实现
- 给程序统一设置
- 给每个线程单独设置
- 给线程池设置
1、自己的UncaughtExceptionHandler
/**
* MyUncaughtExceptionHandler
*
* @author venlenter
* @Description: 自己的UncaughtExceptionHandler
* @since unknown, 2020-04-28
*/
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、使用自己的UncaughtExceptionHandler,触发
/**
* UseOwnUncaughtExceptionHandler
*
* @author venlenter
* @Description: 使用自己的UncaughtExceptionHandler
* @since unknown, 2020-04-28
*/
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捕获了异常MyThread-1异常java.lang.RuntimeException
四月 28, 2020 11:34:06 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
警告: 线程异常,终止了MyThread-1
java.lang.RuntimeException
at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptionHandler.java:24)
at java.lang.Thread.run(Thread.java:748)
四月 28, 2020 11:34:06 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
捕获器1捕获了异常MyThread-2异常java.lang.RuntimeException
警告: 线程异常,终止了MyThread-2
java.lang.RuntimeException
at ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.UseOwnUncaughtExceptionHandler.run(UseOwnUncaughtExceptionHandler.java:24)
at java.lang.Thread.run(Thread.java:748)
四月 28, 2020 11:34:07 下午 ConcurrenceFolder.mooc.threadConcurrencyCore.uncaughtexception.MyUncaughtExceptionHandler uncaughtException
...
3、线程的未捕获异常-常见面试问题
(1)为什么要全局处理?如何全局处理异常?不处理行不行?
- 为什么要全局处理:统一处理,方便,不用每个地方都处理
- 如何全局处理:定义一个自己的UncaughtExceptionHandler,然后Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器1"));
- 必须得处理
(2)run方法是否可以抛出异常?如果抛出异常,线程的状态会怎么样?
- run没有声明throws exception,所以只能try-catch
- 如果在run中try-catch没有捕获,漏了,则会抛出异常,线程会中止运行,打印出堆栈
(3)线程中如何处理某个未处理异常?
- 使用全局处理ExceptionHandler
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》