Java随机数之ThreadLocalRandom学习
[TOC]
问题描述与分析:
为了获取Crash日志,项目中实现了UncaughtExceptionHandler接口对未知异常进行捕获并上传到服务器中,同时停止App运行。在Android5.0以下系统一直未出现过问题,但是突然发现在Android 5.0以上的机器中这段代码出现了java.lang.InternalError: Thread starting during runtime shutdown(更多异常信息见最后部分的附录),在stackoverflow中得到了一些帮助:这个问题是因为线程开启的太晚了!
什么时候开启线程才算得上“太晚了”呢?
在我的项目中UncaughtExceptionHandler实现类捕获到异常时(也就是UncaughtExceptionHandler接口的uncaughtException方法执行时),开启了一个线程用于上传崩溃日志,而在线程中上传崩溃日志时创建了HttpClient发送网络请求。HttpClient创建时设置了ThreadSafeClientConnManager来管理连接,而在ThreadSafeClientConnManager的源码中又一次开启了线程!也就是说,uncaughtException方法执行时在开启的线程中又开启了新的线程,这样可能会导致uncaughtException方法在执行完成时,“线程中的线程”才start(),而据说uncaughtException方法执行完成后ART环境就shutdown了(uncaughtException方法结束时ART是否会真的shutdown,这一点有待考证,笔者也仅是从其他非官方资料中得知),这种情况下就会抛出java.lang.InternalError: Thread starting during runtime shutdown。
为了验证这个问题,编写了一段简单的代码:实现UncaughtExceptionHandler的uncaughtException方法,在uncaughtException方法中开启一个线程,在这个线程中再开一线程,同时在MainActivity中故意制造一个异常发生,此时果然会出现java.lang.InternalError: Thread starting during runtime shutdown(并不是每次都出现,因为如果uncaughtException方法执行结束之前,两个线程都完成start(),此问题就不会出现)。
解决方法:
避免在uncaughtException方法中出现线程嵌套:针对我的项目,不再去在线程中创建HttpClient(因为HttpClient创建时还会开启线程,这就造成了线程中再次开启线程),而是先创建HttpClient对象,再在线程中使用HttpClient对象。这样就可以确保uncaughtException方法结束之前HttpClient已经被创建,HttpClient中开启线程也就不会有问题。
附异常信息:
1 | 2019-09-05 19:44:52.912 ? E/AndroidRuntime: FATAL EXCEPTION: OfflineDownloader |