前言:线程池和AsyncTask是开发中常用的两个工具,那么它们之间到底有什么关系呢?我们应该如何选择呢?接下来让我们一同来探讨。
一、为什么需要引入线程池?
相信很多人都遇到过大量线程并发执行这种情况,譬如说大量图片的下载。那么问题就来了,对于这种大量的并发任务,若是采用常规的做法,为每一张图片的下载均为之开启一个单独的工作线程,并且在完成图片下载之后销毁这个线程。那么这种情况必然会导致频繁的线程创建和销毁,带来大量的开销,更甚者会因为创建了大量的线程而资源耗尽。因此我们想到,能不能在限制线程数量的同时,对这些线程进行复用呢?于是,线程池就诞生了。
这其实运用到了设计模式中的对象池模式(Object Pool),作用如下:
a.复用线程池中的线程,减少了创建和销毁线程的开销。
b.限制系统中并发线程的数量,防止资源耗尽。
c.对线程进行简单的管理,譬如提供定时执行以及制定间隔循环执行等功能。
二、线程池:
1.Android中的资源池其实来源于Java。线程池的实现是ThreadPoolExecutor。Java中有一个Executors工厂,这个工厂类提供了许多静态方法用于创建不同类型的线程池。创建自定义的线程池一般需要指定以下的参数。
a.corePoolSize:代表的是线程池的核心线程数量,一般来说,核心线程会在线程池中一直存活,即便处于空闲状态(没有执行任务的状态)。但是也可以通过将ThreadPoolExecutor的allowCoreThreadTimeOut()设置为true,那么核心线程在空闲的时候会有超时的策略。
b.maximumPoolSize:代表线程池能够容纳的最多的线程数量。当线程数量达到这个数值后,后续的任务将会被阻塞。
c.keepAliveTime:设置非核心线程空闲时的超时时长,一旦达到这个限制,线程就会被回收。当设置ThreadPoolExecutor的allowCoreThreadTimeOut()为true时,这个超时限制也可以作用于核心线程。
d.unit:指定keepAliveTime参数的时间单位。
e.workQueue:代表线程池中的任务队列,通过execute()提交的任务都会加到这个队列中。
f.threadFactory:线程工厂,为线程池提供创建线程的功能。
2.ThreadPoolExecutor执行任务时遵循的规则
a.如果线程池中的线程数量少于核心线程,那么直接启动一个核心线程来执行任务。
b.如果线程池中的线程数量大于等于核心线程数量,那么任务会被放入任务队列中进行等候。
c.如果在b中任务队列已满,也就是无法将任务插入队列的时候。若此时线程数量未达maximumPoolSize指定的最大线程数量,那么系统启动非核心线程来执行任务。
d.若是c中线程数量已经达到了maximumPoolSize指定的最大线程数量,那么线程池将会拒绝任务。
3.Android中的几种线程池:
a.FixedThreadPool:线程数量固定,并且均为核心线程(也就是没有maximumPoolSize一说)。因为均为核心线程,因此可以快速响应外界请求。没有超时机制,也没有任务队列大小限制。
b.SingleThreadExecutor:相当于前者的简单版,只有一个核心线程,确保了所有的任务串行执行,不需要处理同步的问题。
c.CachedThreadPool