熟悉Java的朋友都知道,对异常的捕获和处理对于Java来说是很重要的一项工作。在java中所有的异常都继承于Throwable,统分为两类:未检查异常和已检查异常,已检查异常需要我们在编程时提前进行{try catch },但是未检查异常(派生于Error和RuntimeException)我们在编程时无法进行捕获,但是当程序运行过程中,发生未检查异常会导致例如无法回收一些系统资源,没有关闭当前的连接等等,而且也不知道错误出现在什么地方(当项目需要很健壮的日志记录系统时)。默认的行为是将堆栈跟踪信息写到 控制台中(或者记录到错误日志文件中)然后退出程序
在JDK5.0以后,我们可以通过Thread的实例方法setUncaughtExceptionHandler来进行处理这类问题,,该方法的Api说明:通过明确设置未捕获到的异常处理程序,线程可以完全控制它对未捕获到的异常作出响应的方式。如果没有设置这样的处理程序,则该线程的 ThreadGroup 对象将充当其处理程序。
下面是一个范例:
package uncatchException;
public class ThreadTest {
public static void main(String[] args){
//开启一个线程
Thread arrayA =new Thread(new ArrayThread());
//设置线程A的未检查异常处理程序
arrayA.setUncaughtExceptionHandler(new ErrorHandler());
//Thread.setDefaultUncaughtExceptionHandler(new ErrorHandler());
arrayA.start();
long start= System.currentTimeMillis();
while(true){
try {
Thread.sleep(5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while((System.currentTimeMillis()-start)>10*1000){}
System.out.println("打印当前Thread的状态:"+arrayA.getName() +" "+arrayA.getState());
}
}
}
程序说明:在主线程中开启一个一个线程,在该线程中,我将定义一个5个元素的数组,然后进行打印,在最后打印第六个元素,会报一个运行时异常:java.lang.ArrayIndexOutOfBoundsException。如下:
package uncatchException;
public class ArrayThread implements Runnable {
<span style="white-space:pre"> </span>int[] a={1,2,3,4,5};
<span style="white-space:pre"> </span>int i=0;
<span style="white-space:pre"> </span>boolean isAlive=true;
<span style="white-space:pre"> </span>public void run(){
<span style="white-space:pre"> </span>while(isAlive){
<span style="white-space:pre"> </span>for(int j : a){
<span style="white-space:pre"> </span>System.out.println("a["+(j-1)+"]: "+j);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>Thread.sleep(5*1000);
<span style="white-space:pre"> </span>} catch (InterruptedException e) {
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>for(int i=3;i<6;i++){
<span style="white-space:pre"> </span>System.out.println("a["+i+"]: "+a[i]);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>System.out.println("信息打印完毕");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
}
当发生异常时,系统会调用ErrorHandler作为异常处理程序进行处理,可以在该程序中将异常信息,异常原因进行记录,也可以向监控中心进行汇报等处理。
package uncatchException;
import java.lang.Thread.UncaughtExceptionHandler;
public class ErrorHandler implements UncaughtExceptionHandler {
/**
* 可以进行任何针对异常的处理,比如记录等
*/
public void uncaughtException(Thread a, Throwable e){
System.out.println("a的状态: "+a.getName()+" "+a.getState());
System.out.println("-异常- "+a.getName()+", 信息:"+e.toString());
e.printStackTrace();
}
}
通过继承类UncaughtExceptionHandler ,实现uncaughtException方法来完成处理:
package uncatchException;
import java.lang.Thread.UncaughtExceptionHandler;
public class ErrorHandler implements UncaughtExceptionHandler {
/**
* 可以进行任何针对异常的处理,比如记录等
*/
public void uncaughtException(Thread a, Throwable e){
System.out.println("a的状态: "+a.getName()+" "+a.getState());
System.out.println("-异常- "+a.getName()+", 信息:"+e.toString());
e.printStackTrace();
}
}
通过这种方式,不论在程序调试还是正式上线后,当发生未检查异常时可以及时的进行打印,处理。可以有效的杜绝宕机。
<pre name="code" class="plain">a[0]: 1
a[1]: 2
a[2]: 3
a[3]: 4
a[4]: 5
a[3]: 4
a[4]: 5
a的状态: Thread-0 RUNNABLE
-异常- Thread-0, 信息:java.lang.ArrayIndexOutOfBoundsException: 5
打印当前Thread的状态:Thread-0 TERMINATED
/**
*这部分异常
**/
-异常- Thread-0, 信息:java.lang.ArrayIndexOutOfBoundsException: 5
<span style="white-space:pre"> </span>at uncatchException.ArrayThread.run(ArrayThread.java:18)
<span style="white-space:pre"> </span>at java.lang.Thread.run(Unknown Source)
如果对于多线程的程序来说,尤其使用线程池来新增线程的,当某个线程发生未检查异常时,线程无法正常结束,导致线程池的数量一直在累加。可以通过异常处理进行处理。