ExecutorService的submit⽅法使⽤过程中的坑和源码剖析
最近在项⽬中集成了LeakCanry 来检测项⽬中出现内存泄漏,结果发现了EventBus 导致的内存的泄漏,然后引出了ExecitorService 的submit⽅法会catch掉所有的异常的问题(包含运⾏时异常)。
1, Java中的异常之RuntimeException
下⾯的链接是关于Runtime Exception 的描述:
1.1 运⾏时异常的概念
运⾏时异常是Java编程语⾔的所有的异常的⽗类;当运⾏时异常
发⽣的时候,程序或者应⽤应该崩溃。跟其他的不是运⾏时异常不同,运⾏时异常永远不会被检查。
小学生英语故事
硫在空气中燃烧运⾏时异常通常显⽰程序员的错误,⽽不是程序处理的条件。当⼀个条件不能发⽣的时候,运⾏时的异常也会被使⽤到。应该注意的是:当让⼀个程序的内存⽤完了,⼀个程序的错误会被抛出⽽不是显⽰运⾏时异常。
1.2 常见的运⾏时异常
下⾯是常见的运⾏时异常:
NullPointerException
ArrayIndexOutOfBoundsException新东方泡泡英语
InvalidArgumentException
helixIllegalArgumentExeception
1.3 使⽤ExecutorService 的submit ⽅法之后导致,运⾏时的异常被catch 的问题
下⾯的截图是:
shorter
上⾯LeakCanry 扫描应⽤得到了关于EventBus没有解注册⽽导致了内存的泄漏,正常的代码的逻辑肯定是有解绑的操作。现在出现的问题就是为什么下⾯的解绑的操作没有被调⽤到:
这段代码是在ExecutorService 的submit⽅法⾥⾯调⽤的,通过推理,我们很容易得到,在这个⽅法⾥⾯在EventBus 解绑之前可能抛出了运⾏时的异常,从⽽导致在抛出异常之后的代码未被执⾏。下⾯的截图果然验证我的猜想:
自考培训结果应⽤层抛出了IllegalArgumentExeception.那么现在的问题来了,在运⾏时异常的概念⾥⾯我们知道,发⽣了运⾏时的异常时,应该程序应该会崩溃才对,为什么这⾥发⽣了运⾏时异常,程序没有崩溃?研究了ExecutorService的源码之后,这个疑问就得到解决了。bin是什么
2,ExecutorService ⽅法的源码剖析
krait⾸先我们使⽤Navigate⼯具栏的Type Hierarchy ⼯具查看ExecutorService 的继承的关系:
ExecutorService 的submit ⽅法最后调⽤的是AbstractExecutorService 的submit⽅法:
gre送分newTaskFor⽅法返回的是⼀个FutureTask 对象。
FutureTask被执⾏的时候,调⽤的是FutureTask 的run ⽅法,如下图所⽰
结果⾥⾯的异常被tExecption ⽅法吸收掉了,并没有抛出来。所以出现了上⾯的问题。即IllegalArgumentExeception被ExecutorService 的submit⽅法Catch了。
英文空间名字
3,总结
使⽤ExecutorService 的时候尽量优先使⽤execute⽅法替代submit ⽅法,避免submit⽅法try catch 掉运⾏时异常,从⽽导致内存泄漏等等问题。ExecuteService 使⽤了execute⽅法之后,应⽤就会崩溃,出现下⾯的界⾯,我们只需要解决代码的错误即可解决。
后记:最近看了刘未鹏的《暗时间》⼀书,就下定决定⾃⼰加⼊写博客的⾏列。书中有⼀句话说的很
好:“写是更好的⼀种思考的⽅式。”我们常常把思考挂在嘴边,却从未去反思⾃⼰:何为思考?何为更好的思考⽅式。读了《暗时间》之后我找到了答案:⽤⼼写作,⾄少坚持8年。我想8年之后我再回头看看⾃⼰曾写过的⽂章,会不会有点感悟?当然时间会告诉我答案。⽤我喜欢的苏东坡的⼀⾸诗⾥⾯的⼀句话:“⼈⽣到处知何似,应是飞鸿踏雪泥。泥上偶然留指⽖,鸿飞那复计东西。”希望在以后的岁⽉回顾起曾经的⾃⼰,像飞鸿在泥上留下指⽖⼀样,给⾃⼰留⼀些东可以思量和回忆的东西。