Java多线程异常处理
UncaughtExceptionHandler处理未捕获的异常
多线程的异常的有别于主线程的异常,多线程的异常异常一般只能在各自的run()方法中进行try-catch,外层的主线程使用try-catch,一般情况下对线程异常无法成功捕获。这是因为在线程Thread类中有一个接口 UncaughtExceptionHandler,它包含了一个uncaughtRxception()方法。当线程运行时候出现了异常而终止的时候,但该异常又没有try-catch的时候就会触发此方法,由于Java的Thread类默认使用uncaughtException()进行空处理,而 Java 虚拟机又会忽略该方法之后的异常抛出。所以就导致在外线程无法对内线程进行try-catch,捕获到内线程的异常。源码如下
@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);
}
使用UncaughtExceptionHandler处理未捕获的异常
- 编写自定义的异常处理类,实现Thread.UncaughtExceptionHandler接口重写其 uncaughtException方法
- 编写一个类实现ThreadFactroy接口类,重写其newThread方法,通过setUncaughtExceptionHandler将自定义异常处理类设置为Thread的默认异常处理类。
// 1.编写自定义异常处理类
class SuccessCatchThreadExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName()+"抛出了异常:"+e.toString());
}
}
// 2.通过线程处理异常工厂类,将自定义线程处理异常处理类放入并运行
class SuccessCatchThreadExceptionFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread tmpThread = new Thread(r);
tmpThread.setUncaughtExceptionHandler(new SuccessCatchThreadExceptionHandler());
return tmpThread;
}
}
运行结果展示
public class MyTryThread {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool(
new SuccessCatchThreadExceptionFactory()
);
executorService.execute(new DividerByZeroRunnable());
}
}
class DividerByZeroRunnable implements Runnable{
@Override
public void run() {
int dividend = 30 ;
int divisor = 3;
int step =1;
while(divisor >= 0){
System.out.println(dividend+"与"+divisor+"相除结果为:"+dividend/divisor);
divisor--;
}
System.out.println("结束运算");
}
}
//结果
30与3相除结果为:10
30与2相除结果为:15
30与1相除结果为:30
Thread-0抛出了异常:java.lang.ArithmeticException: / by zero
Process finished with exit code 0
线程内run()进行异常处理
public class TryThread {
public static void main(String[] args) {
Thread thread01 = new Thread(new TrowsExceptionRunnable());
try{
thread01.start();
}catch (Exception e){
System.out.println("成功在main()方法捕获到异常!");
}
}
}
class TrowsExceptionRunnable implements Runnable {
@Override
public void run() {
int dividend = 30 ;
int divisor = 3;
int step =1;
while(divisor >= 0){
try{
System.out.println(dividend+"与"+divisor+"相除结果为:"+dividend/divisor);
}catch(Exception e){
System.out.println("成功在run()方法中捕获到线程异常!");
}
divisor--;
}
System.out.println("结束运算");
}
}
// 从结果可以发现 在main线程中没有捕获到内部线程的异常
30与3相除结果为:10
30与2相除结果为:15
30与1相除结果为:30
成功在run()方法中捕获到线程异常!
结束运算
Process finished with exit code 0
Future的get()方法获取异常
public class FutureCatchExceptionDemo {
public static void main(String[] args) {
Callable<String> getSubString = new SubStringCallable();
FutureTask<String> stringFutureTask = new FutureTask<String>(getSubString);
Thread subStringThread = new Thread(stringFutureTask);
subStringThread.start();
try{
System.out.println(stringFutureTask.get());
}catch (Exception e){
System.out.println("返回子字符串失败了,应该是截取越界!");
}
}
}
class SubStringCallable implements Callable<String>{
@Override
public String call() throws Exception {
String fullInfoString = "我是AAA字符串,据说我要被截取一小段,然后返回....";
String tmpSubString = fullInfoString.substring(15,30);
return tmpSubString;
}
}
call()方法包含 throws Exception 的能力,即当线程内部发生异常的时候可以抛出给外层线程进行捕获。主要是通过Future的get()方法得到call()方法的返回值,来进行外层的异常捕获。
//结果
返回子字符串失败了,应该是截取越界!
Process finished with exit code 0