提出问题
线程的run方法向外可以抛出异常吗,或者能被主线程捕获异常吗?比如下面这段代码:
public static void main(String[] args) {
try {
new Thread(()->{
throw new Exception();
}).start();
}catch (Exception e){
System.out.println("捕获异常!");
}
}
能被外部主线程捕获到异常吗?如果你用的是比较智能的IDE,应该在编写这段代码时就会直接报错:未报告的异常错误java.lang.Exception; 必须对其进行捕获或声明以便抛出
,可见外部是捕获不到这个异常的,同理,下面这段代码会产生一个RuntimeException,在主线程中也不能对其进行捕获:
public static void main(String[] args) {
try {
new Thread(()->{
int i = 1/0;
}).start();
}catch (Exception e){
System.out.println("捕获异常!");
}
}
处理线程内部异常的方法
try-catch
由此可知,java线程内部产生的异常应当在线程内部进行处理,最典型的方法是在线程内部使用try...catch...
捕获异常。
但是,如果不想使用try-catch
,有没有其他的办法呢?
UncaughtExceptionHandler
JDK提供了一个类称为UncaughtExceptionHandler
,翻译过来是未捕获异常处理器,可以把它看作线程的全局异常处理器,会处理所有的RuntimeException异常,因为它是非受查的。
给线程设置一个UncaughtExceptionHandler
有两个方法,一个是直接使用Thread的成员方法setUncaughtExceptionHandler
,是为调用该方法的线程设置异常处理器:
public static void main(String[] args) {
Thread thread = new Thread(()->{
int i = 1/0;
},"thread1");
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("在"+Thread.currentThread().getName()+"中进行处理异常:");
System.out.println(e.getClass().getName());
}
});
thread.start();
}
另一种方法是通过Thread.setDefaultUncaughtExceptionHandler
静态方法,为所有线程设置一个异常处理器:
public static void main(String[] args) {
Thread thread = new Thread(()->{
int i = 1/0;
},"thread1");
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("在"+Thread.currentThread().getName()+"中进行处理异常:");
System.out.println(e.getClass().getName());
}
});
thread.start();
}
上面这两段程序运行之后都可以看到异常是在哪进行处理的:
在thread1中进行处理异常:
java.lang.ArithmeticException
可见还是在子线程中进行处理的,那么有没有能在主线程中处理异常的方法呢?
TaskFuture+Callable触发异常
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> futureTask = new FutureTask<>(()->{
int i = 1/0;
return i;
});
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
运行这段程序,查看错误流输出:
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.rhett.thread.TestCatch.main(TestCatch.java:16)
Caused by: java.lang.ArithmeticException: / by zero
at com.rhett.thread.TestCatch.lambda$main$0(TestCatch.java:9)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:748)
可以看到,触发了一个ExecutionException
异常,并且是在主线程内触发的,它的stacktrace信息和caused by信息都说明了是因为子线程中的哪个异常而引起的ExecutionException
,通过下面这个程序就可以在主线程中处理异常了:
public static void main(String[] args) throws InterruptedException, ExecutionException {
FutureTask<Integer> futureTask = new FutureTask<>(()->{
int i = 1/0;
return i;
});
Thread thread = new Thread(futureTask);
thread.start();
try {
System.out.println(futureTask.get());
}catch (ExecutionException e){
System.out.println(e.getCause());
}
}
原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e7%ba%bf%e7%a8%8b%e5%86%85%e9%83%a8%e7%9a%84run%e6%96%b9%e6%b3%95%e5%8f%af%e4%bb%a5%e5%90%91%e5%a4%96%e6%8a%9b%e5%87%ba%e5%bc%82%e5%b8%b8%e5%90%97%ef%bc%9f/