Android AsyncTask两种线程池分析和总结

转载 2016年06月01日 16:55:54
本文转载自:http://bbs.51cto.com/thread-1114378-1.html
(一)    前言
在android AsyncTask里面有两种线程池供我们调用
1.    THREAD_POOL_EXECUTOR, 异步线程池
2.    SERIAL_EXECUTOR,同步线程池
正如上面名称描述的那样,一个是异步线程池,多个任务在线程池中并发执行;还有一个是同步执行的。
默认的话,直接调用execute的话,是使用SERIAL_EXECUTOR
下面的话,会用源代码的方式来说明这两种线程池的作用和注意事项。
(二)     THREAD_POOL_EXECUTOR用法举例
1.    代码

2.    使用方法比较简单,首先创建一个继承自AsyncTask的MyAsyncTask类,然后调用

MyAsyncTask asynct = newMyAsyncTask(task);
asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,0);

就可以了。
3.    上面代码执行的时候会出错,导致程序异常终止,如下图
 
原因是:


就是因为我们尝试添加500个task到AsyncTask.THREAD_POOL_EXECUTOR线程池中,但是它的核心线程是5,队列容量是128,最大线程数是9。
所以,抛出了这个异常。
那么,接下来的话,我们会去分析这个异常怎么出来的。

(三)     THREAD_POOL_EXECUTOR代码分析
从AsyncTask.THREAD_POOL_EXECUTOR的定义开始分析
1.    代码路径
frameworks\base\core\java\android\os\AsyncTask.java

代码:

privatestaticfinal int CPU_COUNT = Runtime.getRuntime().availableProcessors();
privatestaticfinal int CORE_POOL_SIZE = CPU_COUNT + 1;
privatestaticfinal int MAXIMUM_POOL_SIZE = CPU_COUNT * 2+1;
privatestaticfinal int KEEP_ALIVE = 1;
....
/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
 publicstaticfinal Executor THREAD_POOL_EXECUTOR = newThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                 TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

那么,继续往下面看,看这几个参数传进去后是什么意思。

2.    代码路径
\libcore\luni\src\main\java\java\util\concurrent\ThreadPoolExecutor.java

代码:


这是ThreadPoolExecutor的构造函数,首先需要明白的是这几个参数的含义
A.    corePoolSize: 线程池维护线程的最少数量
B.    maximumPoolSize:线程池维护线程的最大数量
C.    keepAliveTime: 线程池维护线程所允许的空闲时间
D.    unit: 线程池维护线程所允许的空闲时间的单位
E.    workQueue: 线程池所使用的缓冲队列
F.    handler: 线程池对拒绝任务的处理策略

当一个任务通过asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0)方法欲添加到线程池时:
如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。

也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

unit可选的参数为java.util.concurrent.TimeUnit中的几个静态属性:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS。

workQueue是BlockQueue的子类,ArrayBlockingQueue,DelayQueue

handler有四个选择(这不是android的Handler):
ThreadPoolExecutor.AbortPolicy() – 这个也是AsyncTask.THREAD_POOL_EXECUTOR使用的
抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()
重试添加当前的任务,他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()
抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy()
抛弃当前的任务

所以,正是我们的AsyncTask.THREAD_POOL_EXECUTOR使用了AbortPolicy()类型的handler,所以才会抛出异常..

那么,在把任务添加到AsyncTask.THREAD_POOL_EXECUTOR之后,下面的工作就是由这个线程池来调度线程执行任务了。

(四)     AsyncTask. SERIAL_EXECUTOR
1.    使用方法
AsyncTask. SERIAL_EXECUTOR的使用方法和Async.THREAD_POOL_EXECUTOR差不多。不过正如前面所说,它是默认的Executor,所以可以直接调用,所以可以有两种调用方法。

a.    asynct.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, 0);

b.    asynct.execute(0);
效果是一样的

2.执行流程
代码路径:
frameworks\base\core\java\android\os\AsyncTask.java

代码:


嗯,它会调用到SerialExecutor.execute(Runnable r)方法
在这个方法里面,它首先把任务放到mTasks这个集合里面;然后判断mActivie是否为空,再调用scheduleNext ()方法。
mActivie为null的意思是当前没有任务在执行,如果mActivie!=null,那么说明当前有任务正在执行,那么只要把任务添加到mTasks里面即可。
因为任务执行完毕后,会再次调用scheduleNext()方法的,就是
finally {

  scheduleNext();

}

这样就形成了一种链状调用结构,只要mTasks里面还有任务,就会不断逐一调用,如果后面有任务进来,就只要添加到mTasks里面即可。
同时,不知道大家注意到没有,这两个方法都是synchronized的,这样,就保证了多线程之间调度问题。
否则肯定会出现问题的,至于什么问题,大家想想就能明白。

4.    继续分析scheduleNext()方法
这个方法首先把mTasks里面的数据取一个出来,然后调用
THREAD_POOL_EXECUTOR.execute(mActive);
我晕,这不就是上面一直在分析的AsyncTask.THREAD_POOL_EXECUTOR么?
好吧,原来AsyncTask.THREAD_POOL_EXECUTOR和AsyncTask.SERIAL_EXECUTOR的区别就是SERIAL_EXECUTOR在THREAD_POOL_EXECUTOR的基础上添加了一个mTasks的集合来保证任务顺序执行而已...

(五)     总结
说了这么多,总结下
1.    AsyncTask里面有THREAD_POOL_EXECUTOR和SERIAL_EXECUTOR两种方式来异步执行任务;THREAD_POOL_EXECUTOR是异步的,而SERIAL_EXECUTOR任务是顺序执行的。
2.    THREAD_POOL_EXECUTOR如果添加的任务过多,没有及时处理的话,会导致程序崩溃,它的队列size是128;它的调度规则是核心池大小,队列大小,以及最大线程数和异常处理Handler来决定的。
3.    SERIAL_EXECUTOR本质是在THREAD_POOL_EXECUTOR的基础上添加一个mTasks的集合来保证任务的顺序执行。

参考网址
http://blog.sina.com.cn/s/blog_8417aea80100t483.html

Android实战技巧:深入解析AsyncTask

AsyncTask的介绍及基本使用方法 关于AsyncTask的介绍和基本使用方法可以参考官方文档和Android实战技巧:多线程AsyncTask这里就不重复。 AsyncTask引发的一个问题...
  • hitlion2008
  • hitlion2008
  • 2012年09月16日 00:02
  • 94121

AsyncTask优缺点(两种线程池)

AsyncTask两种线程池  http://bbs.51cto.com/thread-1114378-1.html (API 3.0以后): 1.THREAD_POOL_EXECUTOR, ...
  • ai_yong_jie
  • ai_yong_jie
  • 2016年08月04日 10:02
  • 2253

Android多线程任务优化1:探讨AsyncTask的缺陷

导语:在开发Android应用的过程中,我们需要时刻注意保障应用的稳定性和界面响应性,因为不稳定或者响应速度慢的应用将会给用户带来非常差的交互体验。在越来越讲究用户体验的大环境下,用户也许会因为应用的...
  • mylzc
  • mylzc
  • 2011年09月17日 12:02
  • 35175

解决AsyncTask的线程池限制问题

这是一篇我个人在EOE发的帖子《解决AsyncTask的线程池限制问题》,由于eoe的blog系统实在是无言以对,我就把eoe上面的帖子以及blog是都转到csdn上来,原帖地址:http://www...
  • lsmfeixiang
  • lsmfeixiang
  • 2014年12月28日 13:05
  • 1374

AsyncTask中的线程池

今天碰到Webveiw初始化时候居然跟AsyncTask的线程池有关,做些整理。 1、线程池 AsyncTask的执行有两种execute和executeOnExecutor,一种是使用默认线程池,一...
  • u012164786
  • u012164786
  • 2016年08月04日 15:58
  • 571

Android系统分析之AsyncTask源码解析

1 AsnyncTask 1.1 概念 首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避...
  • chenliguan
  • chenliguan
  • 2017年01月11日 18:32
  • 498

Android AsyncTask两种线程池分析和总结

(一)    前言 在android AsyncTask里面有两种线程池供我们调用 1.    THREAD_POOL_EXECUTOR, 异步线程池 2.    SERIAL_EXECUTOR...
  • cq_async
  • cq_async
  • 2016年03月19日 22:20
  • 241

Android中的线程池和AsyncTask异步任务(一)

前言:线程池和AsyncTask是我们在多线程并发中经常会使用到的,那么到底它们是怎样工作的呢?又有什么区别呢?该如何选择呢?下面让我们一起来探讨。不恰当的地方还请指教!注:原创,转载请注明出处。一、...
  • sinat_34596644
  • sinat_34596644
  • 2016年04月10日 13:13
  • 1191

Android开发之线程池使用总结

线程池算是Android开发中非常常用的一个东西了,只要涉及到线程的地方,大多数情况下都会涉及到线程池。Android开发中线程池的使用和Java中线程池的使用基本一致。那么今天我想来总结一下Andr...
  • u012702547
  • u012702547
  • 2016年08月20日 20:49
  • 22582

Android开发——Android中常见的4种线程池(保证你能看懂并理解)

0.前言使用线程池可以给我们带来很多好处,首先通过线程池中线程的重用,减少创建和销毁线程的性能开销。其次,能控制线程池中的并发数,否则会因为大量的线程争夺CPU资源造成阻塞。最后,线程池能够对线程进行...
  • SEU_Calvin
  • SEU_Calvin
  • 2016年09月03日 10:44
  • 32984
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android AsyncTask两种线程池分析和总结
举报原因:
原因补充:

(最多只允许输入30个字)