Android - 线程池介绍及使用
使用背景:
在我们的应用中,涉及到多线程,肯定会联想到线程池。例如:一个List列表中每个Item项都需要下载一张图片来显示,如果使用子线程,每一项都需要新起一个子线程来下载。这样做的后果是,不断的创建线程,用完之后便销毁,这样造成频繁的GC回收,严重影响性能。并且,线程太多不便管理,如果用户将列表滑出屏幕,此时并不需要继续下载,要想停止滑出屏幕的线程会显得格外麻烦。这种情况下,我们会首选线程池。
线程池介绍:
android中为我们提供了ThreadPoolExecutor的类来创建线程池。其构造方法有多种,下面介绍一种参数最多的构造方法。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
...
}
依照惯例逐个介绍一下,便于自己的记忆。
corePoolSize:核心线程数
maximumPoolSize:线程池中的线程总数(核心程序+非核心线程);
keepAliveTime:非核心线程空闲时的存活时间。当allowCoreThreadTimeOut属性设为true时,该属性也可用于核心线程;
unit:keepAliveTime的时间单位;
workQueue:阻塞队列。当核心线程以满,剩下的任务放置在阻塞队列中,便于有空闲线程去处理;
threadFactory:用于设置线程名称,创建线程,一般不用设置,使用默认值。
线程池执行策略:
- 当线程数为达到核心线程数,此时创建核心线程来执行剩下的任务;
- 当已达到核心线程数,此时将剩下的任务放入阻塞队列,等待核心线程空闲之后,再从队列中获取执行。
- 当队列中的任务已满,则创建非核心线程来处理剩下的任务,此时的任务不经过阻塞队列。
- 当阻塞队列已满,且线程池中的核心与非核心线程总数也已经达到了最大线程数。此时执行饱和策略,抛出RejectedExecutionException异常
几种常见的线程池:
FixThreadPool,构造方法如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
特征:
1.核心线程数与线程池总数一样,说明没有非核心线程。
2.超时时间为0,表示即使闲置,线程也不会被回收。
- 阻塞队列的队列长度为空,即Integer.MAX_VALUE(2的31次方-1),可以无限往队列中放置任务
使用场景:适用于任务量比较固定但耗时长的任务。
SingleThreadPool,构造方法如下:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
特点: 线程池中只有一个线程,无超时销毁时间,阻塞队列长度为无限大
SingleThreadExecutor的意义在于统一外界所有任务到一个线程,这使得这些任务之间不需要处理线程同步的问题.
使用场景:适用于执行定时任务和具体固定周期的重复任务。
CacheThreadPool,构造方法如下:
public static ExecutorService newCacheThreadPool(int nThreads) {
return new ThreadPoolExecutor(
0,Integer.MAX_VALUE,
60L,TimeUnit.SECONDS,
new SynchronousQueue<Runnable>()
);
}
特点:没有核心线程,非核心线程数量可以无限大,60s超时销毁。阻塞队列使用SynchronousQueue,该队列可以理解为无法储存的队列,只有在可以取出的情况下,才会向其内添加任务.
使用场景:比较适合任务量大但耗时少的任务。
ScheduledThreadPool,构造方法如下:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSzie) {
return new ScheduledThreadPoolExecutor(corePoolSzie);
}
//核心线程数是固定的,非核心线程无限大,并且非核心线程数有10s的空闲存活时间
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize,
Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS,
MILLISECONDS,
new DelayedWorkQueue());
}
特点:它的核心线程数量是固定的,而非核心线程数是没有限制的,并且当非核心线程闲置时会被立即回收.
ScheduThreadPool这类线程池主要用于执行定时任务和具有固定周期的重复任务.
而DelayedWorkQueue这个队列就是包装过的DelayedQueue,这个类的特点是在存入时会有一个Delay对象一起存入,代表需要过多少时间才能取出,相当于一个延时队列。
使用场景:适用于执行定时任务和具体固定周期的重复任务。
OK,暂时到这里,有空会继续更新线程池的API使用及意义。