记一次arouter跳转异常

现在的arouter动态跳转是通过实现IInterceptor接口来做的


bug复现路径: 任何通过动态跳转的功能连续用10次, 第10次就会没反应, 等待几分钟后突然自动跳转

猜测

这时候并没有出现主线程卡顿, 还没正常响应事件, 也没有什么handler消息屏障之类的特殊逻辑. 我们的router跳转肯定是触发了, 但是没执行.
猜测是有线程池派发任务不及时的问题, 因为主线程并不卡, 即使不知道arouter内部有线程应该也能猜测到.
Profiler查看, 有一堆arouter名字的线程, 全部是阻塞状态


拦截器的工作流程

每次调用Arouter跳转, 都会先经过拦截器(如果有). 拦截器其实就是带这个注解的类





循环遍历拦截器, 每个拦截器都要主动调用callBack.onContinue()才能唤起下一个拦截器, 其实就是网盘每个拦截器的实现里的else逻辑



问题出现的原因

目前项目里有6个拦截器类.
拦截器一层一层执行, 基本都执行了各自的else逻辑, 也就是callBack.onContinue(). 交给下一个拦截器去处理. 这时候countDownLatch已经变成1了.
这时候命中了最后一个拦截器的非else逻辑, 因为我们要拦截这次跳转. 但是看前面的代码, 我们处理完拦截, 并没有调用 callBack.onContinue().
这时候虽然后面已经没有别的拦截器了, 但是countDownLatch还没扣完啊, 还是1, 会阻塞到timeout结束, 硬控300秒

因为countDownLatch阻塞的是线程池里的线程, 等线程全部用尽后, 就会无线程可用, 只能等待超时结束才会执行await()后的代码片段. 现象就是等了几分钟突然继续跳转几分钟前的页面.

为什么是点击第10次才不响应呢?

这是一个core线程= (cpuSize + 1)的线程池, 大部分手机都是8核CPU. 所以前9次都可以创建线程, 但是都会被countDownLatch阻塞住, 用一个阻塞一个.
到第10次的时候, 已经没法创建线程了, 就要等待带超时的countDownLatch.await()调用unpark解锁线程.


解决办法

在出现问题的这个动态路非else逻辑里, 由处理完动态路由任务后, 调用callBack.onContinue() 或者 callBack.onInterrupt().去消费掉countDownLatch, 保证最终归0解除对线程的锁, 让线程池能正常工作.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容