我们都了解线程池的作用,这里不多做赘述。
首先来看线程池的构造函数:
public ThreadExecutor(int corePoolSize, //线程池中的线程数
int maximumPoolSize, //线程池中的最大线程数
long keepAliveTime, //线程数超过指定数值后,多余的空闲线程的存活时间
TimeUnit unit, //线程池维护线程所允许的空闲时间的单位
BlockingQueue<Runnable> workQueue, //被提交但未被执行的任务等待队列
ThreadFactory threadFactory, //线程工厂,用于创建线程
RejectedExecutionHandler handler) //拒绝策略,当提交的任务太多,不够线程处理后,如何拒绝任务
我们看到线程池构造函数有7个参数,参数的作用如上图注释。
线程池中维护的任务队列有许多不同功能的实现,今天我们学习以下四种:
1.直接提交队列:使用的是SynchronousQueue实现的队列。提交到这个队列的任务不是真的保存在队列中,而是立即将任务提交给线程执行,如果线程池中没有线程,则立即创建线程执行,如果线程池中线程数大于最大线程数,则会执行拒绝策略,任务拒绝执行。
2.有界的任务队列: 使用的是ArrayBlockingQueue实现的队列。按照先进先出的算法处理任务。使用它时必须设定一个最大容量参数,当有任务提交到线程池中,首先判断线程池中线程数如果小于核心线程数,则立即创建新线程执行任务,若大于核心线程数则将任务提交到任务队列。如果任务队列满了,再创建新的线程执行任务。直到线程数达到最大线程数。
3.无界任务队列:使用的是LinkedBlockingQueue实现的队列。按照先进先出的算法处理任务。使用时和有界队列正好相反,任务队列没有固定容量,如果线程池中线程大于核心线程数,会将任务一直提交到任务队列,直到内存耗尽。
4.无界优先任务队列:PriorityBlockingQueue实现的队列。不是按照先进先出的算法执行,而是按照任务的优先级进行执行。
如何实现不同功能的线程池的呢?
1.newFixedThreadPool 固定线程数线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
我们看到,ThreadPoolExecutor的构造函数,核心线程数和最大线程数被设置成大小一样,第三个参数,线程存活时间设置成0L,意思是当线程池中有线程空闲时,立刻被停止。第四个参数,使用无界队列作为任务队列,意思是当线程数大于核心线程数时,提交到任务队列,直到内存耗尽。
2.newSingleThreadExecutor 单线程线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
ThreadPoolExecutor的构造函数,核心线程数和最大线程数被设置成1,线程存活时间0L,无界任务队列。保证只有一个线程工作。
3.newCachedThreadExecutor 可缓存线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看到核心线程数为0,最大线程数无穷大,存活时间60L,任务队列是直接提交队列。如果线程池中没有空闲线程,将任务提交到任务队列,直接创建线程去执行,如果空闲60s,由于核心线程数为0,则会被回收。