Java世界里线程无处不在,如果线程抛出了异常,是如何处理的呢?
线程对异常的处理主要涉及到java.lang.Thread.UncaughtExceptionHandler:
当一个线程即将因为一个未捕获的异常而终止时,Java虚拟机会使用getUncaughtExceptionHandler查询线程的未捕获异常处理器,并调用处理器的uncaughtException方法,将线程和异常作为参数传递。如果一个线程没有明确设置其未捕获异常处理器,那么它的ThreadGroup对象就充当其未捕获异常处理器。如果ThreadGroup对象没有特别的要求来处理异常,它可以将调用转发给默认的未捕获异常处理器。
1、线程明确设置其未捕获异常处理器
通过java.lang.Thread#setUncaughtExceptionHandler方法设置此线程的异常处理器,当此线程由于未捕获的异常而突然终止时调用的处理程序,示例如下:
源码:
package com.renzhikeji.demo;
/**
* @author 认知科技技术团队
* 微信公众号:认知科技技术团队
*/
public class ThreadDemo {
public static void main(String[] args) throws Exception{
ThreadGroup threadGroup = new ThreadGroup("认知科技技术团队-ThreadGroup"){
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("threadGroup uncaughtException:"+ e.getMessage());
}
};
Thread thread = Thread
.ofPlatform()
// .group(threadGroup)
.name("认知科技技术团队-thread")
.uncaughtExceptionHandler((t, e) -> {
System.out.println("Thread UncaughtExceptionHandler:"+ e.getMessage());
})
.start(() -> {
throw new RuntimeException("test exception");
});
thread.join();
System.out.println(thread.isAlive());
}
}
执行结果:
2、线程组设置捕获异常处理器
线程组默认的异常处理会一直迭代调用其父线程组的异常处理器,直到父线程组对象为空,最终会调用Thread类全局默认的异常处理器,如果都没有,则会把异常信息输出到标准错误流:
源码:java.lang.ThreadGroup#uncaughtException
我们一般重写线程组设置捕获异常处理器,示例:
package com.renzhikeji.demo;
/**
* @author 认知科技技术团队
* 微信公众号:认知科技技术团队
*/
public class ThreadDemo {
public static void main(String[] args) throws Exception{
//重写线程组异常处理
ThreadGroup threadGroup = new ThreadGroup("认知科技技术团队-ThreadGroup"){
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("threadGroup uncaughtException:"+ e.getMessage());
}
};
Thread thread = Thread
.ofPlatform()
//设置线程组,使用线程组异常处理
.group(threadGroup)
.name("认知科技技术团队-thread")
.start(() -> {
throw new RuntimeException("test exception");
});
thread.join();
System.out.println(thread.isAlive());
}
}
输出结果:
3、线程全局异常处理器
通过java.lang.Thread#setDefaultUncaughtExceptionHandler方法设置全局异常处理器,当线程由于未捕获的异常而突然终止时调用其默认处理器处理,示例如下:
package com.renzhikeji.demo;
/**
* @author 认知科技技术团队
* 微信公众号:认知科技技术团队
*/
public class ThreadDemo {
public static void main(String[] args) throws Exception{
//设置线程全局异常处理器
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("Thread DefaultUncaughtExceptionHandler :"+ e.getMessage());
}
});
Thread thread = Thread
.ofPlatform()
.name("认知科技技术团队-thread")
.start(() -> {
throw new RuntimeException("test exception");
});
thread.join();
System.out.println(thread.isAlive());
}
}
执行结果:
利用线程池处理业务时,有时候需要我们自己对线程异常要捕获,不能过度依赖线程处理器,否则可能导致线程退出。