在A线程里起了另B线程,但B线程报错了,这时想要在A线程里捕获B线程的异常是无法做的,除非在捕获B线程前先设置线程捕获器。直接来看代码:
package com.wulf.exceptionHandler;
import java.lang.Thread.UncaughtExceptionHandler;
public class ExceptionCatcher {
public static void main(String[] args) {
// 1、新线程抛异常,main线程无法捕获
try {
new Thread() {
@Override
public void run() {
System.out.println("第一个空指针来了:");
throw new NullPointerException();
}
}.start();
} catch (Exception e) {
System.out.println("第一次抛出异常!");
}
// 2、通过线程捕获异常
try {
// 先休眠,等上面的线程自动结束
Thread.sleep(1000);
// 先设置捕获线程
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("线程:%s 抛出异常:%s\n", t.getName(), e.getClass().getName());
e.printStackTrace();
}
});
// 新起线程抛出异常
new Thread() {
@Override
public void run() {
System.out.println("第二个空指针来了:");
throw new NullPointerException();
}
}.start();
} catch (
Exception e) {
System.out.println("第二次抛出异常!");
}
}
}
运行结果:
第一个空指针来了:
Exception in thread "Thread-0" java.lang.NullPointerException
at com.wulf.exceptionHandler.ExceptionCatcher$1.run(ExceptionCatcher.java:16)
at java.lang.Thread.run(Thread.java:745)
第二个空指针来了:
线程:Thread-1 抛出异常:java.lang.NullPointerException
java.lang.NullPointerException
at com.wulf.exceptionHandler.ExceptionCatcher$3.run(ExceptionCatcher.java:46)
at java.lang.Thread.run(Thread.java:745)
根据线程执行速度不同,新起的线程里exception和本地线程里字符串的打印顺序先后有可能不同。看下的UncaughtExceptionHandler的源码:
/**
* Interface for handlers invoked when a <tt>Thread</tt> abruptly
* terminates due to an uncaught exception.
* <p>When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* <tt>UncaughtExceptionHandler</tt> using
* {@link #getUncaughtExceptionHandler} and will invoke the handler's
* <tt>uncaughtException</tt> method, passing the thread and the
* exception as arguments.
* If a thread has not had its <tt>UncaughtExceptionHandler</tt>
* explicitly set, then its <tt>ThreadGroup</tt> object acts as its
* <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
* has no
* special requirements for dealing with the exception, it can forward
* the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
* default uncaught exception handler}.
*
* @see #setDefaultUncaughtExceptionHandler
* @see #setUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
@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);
}
上面的注释告诉我们线程查找未捕获异常的顺序:Thread实例的setUncaughtExceptionHandler -> ThreadGroup的setUncaughtExceptionHandler ->
Thread的静态方法Thread.setDefaultUncaughtExceptionHandler。我们把例子改一下:
public class Test {
public static void main(String[] args) {
// 1、新线程抛异常,main线程无法捕获
try {
new Thread() {
@Override
public void run() {
System.out.println("第一个空指针来了:");
throw new NullPointerException();
}
}.start();
} catch (Exception e) {
System.out.println("第一次抛出异常!");
}
// 2、通过线程捕获异常
try {
// 先休眠,等上面的线程自动结束
Thread.sleep(1000);
// 先设置捕获线程
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("[setDefaultUncaughtExceptionHandler] 线程:%s 抛出异常:%s\n", t.getName(), e.getClass().getName());
e.printStackTrace();
}
});
// 新起线程抛出异常
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("第二个空指针来了:");
throw new NullPointerException();
}
};
thread.setUncaughtExceptionHandler((Thread t, Throwable e) -> {
System.out.printf("[setUncaughtExceptionHandler] 线程:%s 抛出异常:%s\n", t.getName(), e.getClass().getName());
e.printStackTrace();
});
thread.start();
} catch (
Exception e) {
System.out.println("第二次抛出异常!");
}
}
}
运行结果:
第一个空指针来了:
Exception in thread "Thread-0" java.lang.NullPointerException
at com.wlf.springcloudgateway.Test$1.run(Test.java:33)
第二个空指针来了:
[setDefaultUncaughtExceptionHandler] 线程:Thread-1 抛出异常:java.lang.NullPointerException
java.lang.NullPointerException
at com.wlf.springcloudgateway.Test$3.run(Test.java:62)