目录
一、为什么要使用线程池
构造一个新的线程是需要较大的系统开销的,如果我们在程序中需要实现大量的生命周期短的线程,如果每个任务都映射到一个单独的线程中,那么系统开销可想而知。那么线程池有什么优点才会使用它呢?线程池中有很多准备运行的线程,当一个线程的任务执行完毕,这个线程不会销毁,而是会留在线程池中等待调用。
二、线程池的优点
1、线程池中的线程会重用,避免线程的创建和销毁带来的系统开销。
2、能有效的控制线程池的最大并发数,避免大量线程之间因相互强占系统资源二导致阻塞现象。
3、能够对线程进行简单的管理。
三、执行器Executors
Android中的线程池其实源于Java中的Executors,执行器Executors类有些静态工厂方法来构造线程池。
方法 | 描述 |
newCachedThreadPool | 必要时创建新线程,空闲线程保持60秒 |
newFixedThreadPool | 池中包含固定数目的线程,空闲线程一直保留 |
newWorkStealingPool | 复杂的任务会分解为更简单的任务 |
newSingleThreadExecutor | 只有一个线程的线程池,顺序执行提交的任务 |
newScheduledThreadPool | 用于调度执行的固定线程池 |
newSingleThreadScheduledExecutor | 用于调度执行的单线程的线程池 |
四、ThreadPoolExecutor
ThreadPoolExecutor是线程池的实现类,它实现了ExecutorService接口。
构造方法如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
参数含义:
1、corePoolSize:线程池的核心线程数。
2、maximumPoolSize:线程池容纳的最大线程数。
3、keepAliveTime:非核心线程数闲置的超时时长,超过这个时长,非核心线程会被回收。
4、unit:指定keepAliveTime参数的时间单位。
5、workQueue:线程池中的任务队列,通过线程池的execute方法提交的Runnable对象会存储在这个参数里面。
6、threadFactory:线程工厂,为线程池提供创建新线程的功能。
五、常用线程池
1、newCachedThreadPool
返回一个缓存线程池,在必要的时候创建线程,如果线程已经空闲60s,则终止此线程。
查看源码,可以看到这个方法返回了实现ExecutorService接口的ThreadPoolExecutor类的对象。其中核心线程数为0,最大容纳线程数为任意大,所以CachedThreadPool只有非核心线程,超时时间为60s,使用的任务队列为SynchronousQueue,这是一个无法存储元素的队列,就相当于是一个空集合,任何任务都会立即执行。CachedThreadPool线程池适用于执行大量耗时较少的任务。当整个线程池都处于闲置状态是,里面的线程都会因超时而停止,这个时候CachedThreadPool里面就没有线程了。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
2、newFixedThreadPool
返回一个线程池,使用给定数目的线程执行任务。如果提交的任务书多余空闲线程数,就会把未得到服务的任务放到队列中,其他任务完成以后再运行这些排队的任务。它的线程数量是固定的,且都是核心线程,核心线程不会回收,能够更快速的响应外界请求。
查看源码,核心线程数和最大容纳线程数是一样的,是调用newFixedThreadPool方法时传入的参数,没有超时时间。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
3、newScheduledThreadPool
返回一个线程池,使用给定数目的线程调度任务。ScheduledExecutorService接口为调度执行或重复执行提供了一些方法。ScheduledThreadPool的核心线程数是固定的,没有限制非核心线程数,当非核心线程闲置时会被回收,ScheduledThreadPool主要用于执行定时任务和具有固定周期的重复任务。
查看源码,ScheduledThreadPool线程池的核心线程数是调用newScheduledThreadPool方法传入的参数,最大容纳线程数为任意大,超时时间为10毫秒,任务队列为DelayedWorkQueue。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor继承ThreadPoolExecutor,实现ScheduledExecutorService接口
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
4、newSingleThreadExecutor
返回一个线程池,在一个单独的线程中顺序的执行任务。线程内部只有一个核心线程,它确保所有的任务都在同一个线程中安顺序执行。意义在于同意所有的外界任务到一个线程中,使得这些任务之间不需要处理线程同步问题。
查看源码,线程池的核心线程数和最大容纳线程数都是1。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}