您的位置:首页 > 其它

程序的崩溃处理UncaughtExceptionHandler

2016-09-20 09:15 393 查看


引言

一般程序崩溃时会退出,同时在控制台输出崩溃时的堆栈信息,如下代码:

运行后,控制台输出:

引发问题的地方在最上面,往下依次是方法调用的链条。


扩展应用

很多时候,我们希望对崩溃进行一些处理,比如将崩溃堆栈保存到文件,或是发送到服务器进行统一分析,例子如下:

查看log.txt文件:

其中Thread[main,5,main],前面main为线程名字,5为优先级(1~10,5为一般优先级),后面main为线程组(ThreadGroup)名字,ThreadGroup采用树形结构,一个树根发散成n叉树,一个ThreadGroup包含1个或多个Thread,《Thinking in Java》对ThreadGroup的设计进行了批判,从使用者的角度看,可以适当了解一下,不必深究其中的设计思想,不过作者说的挺有意思“不承认错误是让别人承担后果,承认错误是让自己承担后果”,类似还拿Vector和ArrayList,Hashtable和HashMap做例子,有兴趣的可以看看其中的章节。


分析

源代码中Thread.java的UncaughtExceptionHandler接口注释说明如下:

就是说程序崩溃时,虚拟机会查询线程的uncaught exception handler,由其处理崩溃的事情。其实Thread有两个变量:

注意 defaultUncaughtExceptionHandler 是静态变量,是对整个Thread而言的,另外注意注释,如果没有显式地设置,将会为null,也就是说没有调用

的话,就没有handler进行处理。

程序崩溃流程如下:

系统分发崩溃消息

根据当前线程判断交由谁处理,如果有uncaughtExceptionHandler,则由它处理,如果没有,则由当前线程的ThreadGroup处理。

ThreadGroup实现了UncaughtExceptionHandler,处理过程如下:

正常来说,ThreadGroup会一直递归调用到根ThreadGroup,然后发现parent==null,所以其实没处理,需要注意的是,在实际中,可能会重写ThreadGroup的uncaughtException,这时流程就变了。
ThreadGroup没有处理就交给Thread的defaultUncaughtExceptionHandler处理。
如果没有defaultUncaughtExceptionHandler,就直接输出异常的名字和打印堆栈信息,也就是一般我们看到的出错信息(一般uncaughtExceptionHandler和defaultUncaughtExceptionHandler没有显式地赋值)。Android中ThreadGroup的uncaughtException方法稍有不同,如下:


扩展

统计的代码里使用的是Thread.setDefaultUncaughtExceptionHandler,在崩溃时,将堆栈信息写入数据库,下次启动时发送到服务器。其中

因为没有显式设置UncaughtExceptionHandler,mExceptionHandler其实是null,相当于又产生了一次空指针异常,可以用try catch捕捉,但是不捕捉也没问题,因为线程的流程走向变化了,运行完uncaughtException中的代码,如果再遇到类似空指针的异常,线程就直接结束了,而这条语句在最后,所以没什么问题,如果插入数据的操作在这条语句之后将不被执行,所以最好还是加个空指针的判断。


要点

异常会改变了程序的走向,一般性的异常需要使用try catch进行处理,由用户控制程序流程;运行时异常(空指针、除0等)不需要try catch处理,它由虚拟机来控制改变程序流程,一般是调用Thread的uncaughtExceptionHandler或是defaultUncaughtExceptionHandler来处理。
uncaughtExceptionHandler或是defaultUncaughtExceptionHandler异常处理的代码其实也是由发触发异常的线程执行的,执行完毕,线程也就结束了。
异常的处理顺序为 uncaughtExceptionHandler -> defaultUncaughtExceptionHandler -> 输出堆栈信息(Android的输出内容前面少了Exception in thread "main"之类的东西)。
在uncaughtException方法中,如果再出现空指针之类的异常,线程就此停止,后续的代码将不再执行。
uncaughtExceptionHandler是对当前线程而言,defaultUncaughtExceptionHandler是对所有线程而言的,一般程序可能会有多个线程,因此一般的做法是使用defaultUncaughtExceptionHandler。


注意

不管CPU是单核还是多核,操作系统之上是透明的,多任务并发其实是分配时间片。
并发会造成系统整体性能下降,因为并发控制本身是要耗费资源的。
一个程序内启用多个线程其实是增加本程序在系统中的比重,让系统分配更多的时间片来执行本程序的代码。
多线程的同步问题处理不好会造成逻辑混乱,管理线程需要额外的开销,因此使用多线程要慎重,多方面权衡。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  UncaughtExceptionHan