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

事情起源于一个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会让全部的线程串行执行:spa

串行线程池

并且因为SERIAL_EXECUTOR被声明为static,因此,同一个进程里的AsyncTask都会共享这个线程池,这就意味着,在同一个进程里,前面的线程不结束,后面的线程就会被挂起,这正是我遇到的状况。
接下来排查全部用AsyncTask.execute方法来执行任务的状况,终于找到了一个不合理的调用————在doInBackground里请求网络,一直死等response,而没有超时释放。修复了这种状况,问题就迎刃而解了。线程

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

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

线程池

因此,使用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版本至今,就成了上面说的模样————定义两个线程池,可是默认用串行池。源码

相关文章
相关标签/搜索