博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AsyncTask的小分析
阅读量:6434 次
发布时间:2019-06-23

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

前言

今天项目经理给无(jing)所(pi)事(li)事(jin)的我安排了一个小任务,要在他的专属阅读APP进入首页后加载一张网络上的美女图片,说这样才能安心看书,恩,这还不简单,我第一时间想到了AsyncTask。

实现

protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        /*......                        此处省略1万行代码        ......*/                BeautifulGirlTask girlTask = new BeautifulGirlTask();        girlTask.execute();                /*......                        此处省略2万行代码        ......*/    }

搞定,坐等升职加薪迎娶白富美喽。

第二天,项目经理说有时美女图片加载很慢,过很久才出来,严重影响了他学习。学你妹,仔细查了查代码我发现其他同学也为项目经理写了很多AsynTask小任务,难道这之间有什么影响吗。

分析

首先,先写一个用于测试的AsyncTask, doInBackground方法中让线程休眠1秒,来模拟任务执行,并且在任务开始执行时打印出任务id和线程id,

public class TestTask extends AsyncTask
{ private int id; public TestTask(int id) { this.id = id; } @Override protected Void doInBackground(Void... params) { Log.d("morven","morven--- task-"+id+" start"+",tid="+Thread.currentThread().getId()); try { Thread.sleep(1000); } catch (InterruptedException e) { Log.e("TAG", "sleep interrupt"); } return null; }}

然后,循环创建18个任务并执行,

for (int i=0; i<18; i++){    TestTask task = new TestTask(i);    task.execute();}

来看看执行结果:

clipboard.png

每个任务的启动时间都间隔一秒,说明任务执行是线性的,恩,这么一说我想起来某某大牛的blog里说AsyncTask的执行可以是线性的也可以是并发的;从线程id来看,从第9个任务开始都是使用的同一个线程。

再来试试并发执行,我们将task创建并执行的代码改成下面这样,顺便将cpu核心数也打印出来:

int CPU_COUNT = Runtime.getRuntime().availableProcessors();Log.d("morven","morven--- CPU_COUNT="+CPU_COUNT);for (int i=0; i<18; i++){    TestTask task = new TestTask(i);    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);}

看看结果:

clipboard.png

8核手机就是牛,从日志里看task0-8都是在25:59同时触发执行的,task9-17都是在1秒后同时触发执行,观察线程id也能看出,后面9个task重用了前面9个task的线程,噢,线程池里有9个线程,这跟8核有什么关系吗。

源码分析

带着疑问,打开源码看看,

clipboard.png

原来AsyncTask里有两个执行器,一个用于串行执行,一个用于并行执行,这不就是我们熟悉的java.concurrent里的线程池嘛。

先看并行执行的ThreadPoolExecutor,它的前两个参数CORE_POOL_SIZE和MAXIMUM_POOL_SIZE分别定义了线程池的核心线程数和最大线程数,sPoolWorkQueue提供了线程池的工作队列,线程池运行的规则如下:

(1)一个任务被提交给线程池,如果当前线程池中线程数量小于核心线程数(CORE_POOL_SIZE),那么创建一个新的线程去执行任务。
(2)如果任务被提交给线程池后,线程池中线程数量已等于核心线程数,那么看核心线程中是否有空闲线程,如果有则用空闲线程执行任务,否则将任务放入工作队列等待。
(3)如果任务提交后,没有空闲核心线程且工作队列也满了,那么判断当前核心线程数目是否小于最大核心线程数(MAXIMUM_POOL_SIZE),如果小于,那么创建一个新的线程作为核心线程执行该任务。

在源码中,我们看到,CORE_POOL_SIZE被赋值为CPU核心数+1,MAXIMUM_POOL_SIZE赋值为CPU核心数×2+1,

clipboard.png

所以在前面的测试中,AsyncTask创建了9个核心线程,一次可并发执行9个任务。

工作队列的大小为128,

clipboard.png

那么在我的机器上,如果一次提交9+128=137个任务,且这些任务都未执行完,那么工作队列将被放满,后续再提交的(2×8+1=17)-9 = 8个任务将会在新的线程中执行。

我们将任务的sleep时间改为100秒,创建200个task看看:

for (int i=0; i<200; i++){    TestTask task = new TestTask(i);    task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);}
try{    Thread.sleep(100000);}catch (InterruptedException e){    Log.e("TAG", "sleep interrupt");}

看看结果:

clipboard.png

线程池开始创建了9个线程去运行task0-8,后面提交的task都被放入工作队列中了,直到队列中放满128个task,当第138个任务(task-137)提交执行时,线程池创建了新的线程去执行,一共创建了8个,咦,看图中怎么是9个,有个tid=1的线程,恩,当工作队列已满且无法创建新线程时,任务将会被交给handler执行,也就是主线程,所以我们的UI已经卡死不能响应了。

结束语

AsyncTask给开发带来了极大的方便,但作为小白,总觉得交给别人管理的东西总是行为古怪,除非了解管理的机制。oh,我可不想做回原始人哦。

恩,元旦来啦,祝大家开(jia)心(ban)~

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

你可能感兴趣的文章
应用生命周期终极 DevOps 工具包
查看>>
(iOS开发总结)MVC模式
查看>>
关于python进行批量数据备份及部署
查看>>
我的友情链接
查看>>
Oracle(一)
查看>>
极客班C++ STL(容器)第二周笔记
查看>>
备库设置read_only被阻塞
查看>>
微信营销这么做,你就成功了 转载
查看>>
文件系统管理
查看>>
C语言调用python代码
查看>>
csv文件导入导出到mysql
查看>>
redhat 安装Rabbitmq
查看>>
不常关注CSS
查看>>
最近工作的感想
查看>>
flashback table肯定会造成rowid跟着修改
查看>>
Administrator用户被禁用
查看>>
Python文本处理几种方法
查看>>
做脚本练习时的问题
查看>>
我的友情链接
查看>>
Android开发环境搭建全程演示(jdk+eclipse+android sdk)
查看>>