博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
串行还是并行?——记一次 AsyncTask 问题排查
阅读量:6843 次
发布时间:2019-06-26

本文共 1174 字,大约阅读时间需要 3 分钟。

事情起源于一个bug排查,一个AsyncTask的子类,执行的时候发现onPreExecute方法执行了,doInBackground却迟迟没有被调用。

懂AsyncTask一些表面原理的都知道,onPreExecute方法是在主线程执行,doInBackground方法是在后台线程执行,所以很明显是后台线程被卡住了执行不了,所以这就涉及到AsyncTask的原理问题了,查看出现bug的版本——Android 6.0源码可以知道,AsyncTask里面维护着两个线程池,THREAD_POOL_EXECUTOR和SERIAL_EXECUTOR,其中SERIAL_EXECUTOR是默认的线程池:

线程池

如果用AsyncTask.execute(params...)方法来执行任务,就会用到默认的线程池,即SERIAL_EXECUTOR;可以看出SERIAL_EXECUTOR会让所有的线程串行执行:

串行线程池

而且由于SERIAL_EXECUTOR被声明为static,所以,同一个进程里的AsyncTask都会共享这个线程池,这就意味着,在同一个进程里,前面的线程不结束,后面的线程就会被挂起,这正是我遇到的情况。

接下来排查所有用AsyncTask.execute方法来执行任务的情况,终于找到了一个不合理的调用————在doInBackground里请求网络,一直死等response,而没有超时释放。修复了这种情况,问题就迎刃而解了。

除了这种解决前面线程不合理设计的办法,还有没有别的解决方式呢,因为有时候,我们的设计确实是让后台线程死循环,不跳出的。

当然有的,在AsyncTask设计上就考虑到了,前面说到AsyncTask里面还有一个线程池THREAD_POOL_EXECUTOR,从它的初始化参数可以看出,这是一个支持2到4个线程并行的线程池:

初始化参数

所以,使用AsyncTask执行任务的时候,请使用AsyncTask.executeOnExecutor(THREAD_POOL_EXECUTOR)来让你的任务跑在并行的线程池上,避免出现并前面线程阻塞的情况。当然,如果你的CPU核心数够多,2到4个线程的并行度不满足的话,也可以自定义一个线程池来执行AsyncTask,不过这样的话,要注意自己维护这个线程池的初始化,释放等等操作了。

PS:AsyncTask是不是一开始就是被设计成这样的呢?笔者调研了一下,其实Android 1.5刚开始引入AsyncTask的时候,execute方法确实是串行执行的,类定义里面只有SERIAL_EXECUTOR线程池;到1.6版本时,改用并行线程池THREAD_POOL_EXECUTOR,再到3.0版本至今,就成了上面说的模样————定义两个线程池,但是默认用串行池。

转载地址:http://wvdul.baihongyu.com/

你可能感兴趣的文章
我的Android进阶之旅------>Android关于HttpsURLConnection一个忽略Https证书是否正确的Https请求工具类...
查看>>
shell正则表达式匹配样例
查看>>
Sublime Text 的安装和配置
查看>>
数据库设计三大范式
查看>>
为了加速应用物联网,IT高管必须做的6件事
查看>>
查看MYSQL中数据表占用的空间
查看>>
栗蔚:中国云计算“风景独好”
查看>>
使用sqlparse分析SQL语句,及自己写的SQL分析语句
查看>>
搭建国际交流平台 黑龙江海外人才工作站涉及3D打印
查看>>
嵌入式工控机在舞台灯光控制中的应用
查看>>
简单部署边缘计算的五种方式
查看>>
私有云2.0时代来临,OpenStack已上车
查看>>
Every Programmer Should Know These Latency Numbers
查看>>
WCF后续之旅(15): 逻辑地址和物理地址
查看>>
云计算变革十字路口 CIO转型的历史机遇
查看>>
容器化应用的服务可用性
查看>>
memcached的分布式算法-Consistent Hashing
查看>>
韩忠恒:解读Power System智慧运算基础
查看>>
RabbitMQ之死信队列
查看>>
来自Reddit的声音:网络人员对SDN说“不”
查看>>