资讯专栏INFORMATION COLUMN

串行还是并行?——记一次 AsyncTask 问题排查

mo0n1andin / 3509人阅读

摘要:当然,如果你的核心数够多,到个线程的并行度不满足的话,也可以自定义一个线程池来执行,不过这样的话,要注意自己维护这个线程池的初始化,释放等等操作了。

事情起源于一个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版本至今,就成了上面说的模样————定义两个线程池,但是默认用串行池。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67602.html

相关文章

  • AsyncTask异步任务类

    摘要:异步任务的构造方法主要用于初始化线程池先关的成员变量创建一个新的异步任务。所以,我们是必须确保在销毁活动之前取消任务。 目录介绍 01.先看下AsyncTask用法 02.AsyncTask源码深入分析 2.1 构造方法源码分析 2.2 看execute(Params... params)方法 2.3 mWorker和mFuture的创建过程 03.异步机制的实现 04.不同...

    dongxiawu 评论0 收藏0
  • 一次Node项目的优化

    摘要:相关环境由于是一个几年前的项目,所以使用的是这样的。一些小提示本次优化笔记,并不会有什么文件的展示。将异步改为了串行,丧失了作为异步事件流的优势。 这两天针对一个Node项目进行了一波代码层面的优化,从响应时间上看,是一次很显著的提升。 一个纯粹给客户端提供接口的服务,没有涉及到页面渲染相关。 背景 首先这个项目是一个几年前的项目了,期间一直在新增需求,导致代码逻辑变得也比较复杂,接...

    dreamans 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<