目录
- 一. 什么是线程池
- 二. 为什么要使用线程池
- 三. 线程池的参数
- 四. 线程池的工作流程
- 五. 使用Executors 创建常见的功能线程池
一. 什么是线程池
简单来说,线程池就是提前创建好一批线程,当有任务的时候,从池子中取出一个线程去执行该任务,执行结束后,再把线程放回池子中,以备循环使用。
二. 为什么要使用线程池
- 降低资源消耗,线程一个生命周期需要经过创建、调度、销毁过程,使用线程池,可以降低线程创建和销毁的消耗。
- 提高响应速度,当有任务分配过来时,可以直接调度,不需要创建线程,速度快。
- 提高可管理性,使用线程池可以对线程进行统一的分配、调优和监管。
三. 线程池的参数
以标准库的线程池为例,它的参数列表如下:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
下面对这些参数进行介绍:
corePoolSize
:核心线程数,即常备线程数
maximumPoolSize
:最大线程数,常备线程数 + 临时线程数
keepAliveTime
:线程的空闲时间,简单来说,就是临时线程活干完的时候,不会直接销毁临时线程,而是会观察一段时间,如果没有其他任务,再进行销毁。
TimeUnit unit
:时间单位,m、ms等。
workQueue
:工作队列,没有临时线程时,任务太多,核心线程(常备线程)做不完,则把任务存储到工作队列中。
threadFactory
:线程工厂,用来创建线程,一般使用默认的线程工厂就可以了。
handler
:拒绝策略,任务太多了,工作队列满了,就会执行拒绝策略。
常见的拒绝策略:
ThreadPoolExecutor.AbortPolicy:拒绝任务,抛出异常(直接拒绝,和领导吵一架)。
ThreadPoolExecutor.CallerRunsPolicy:由调用者来执行该任务(拒绝任务,让领导去做)。
ThreadPoolExecutor.DiscardOldestPolicy:把新任务加入,丢弃最早的任务。
ThreadPoolExecutor.DiscardPolicy:直接拒绝,什么也不做。
四. 线程池的工作流程
- 线程池刚创建时,线程池是一个空的,没有任何线程。
- 随着任务的提交,线程池开始创建线程:
a. if (当前线程数 < corePoolSize) ,创建线程
b. if (当前线程数 == corePoolSize) ,则把任务添加到工作队列中去
c. 队列满了,if (当前线程数 < maximumPoolSize) ,创建线程(此时创建的为临时线程)
d. 队列满了,if (当前线程数 == maximumPoolSize) ,执行拒绝策略 - 随着任务的执行,任务逐渐减少,线程有了空闲时间,则:
if(空闲时间 > keepAliveTime && 当前线程数 > corePoolSize),则销毁线程,直到 当前线程数 == corePoolSize。
五. 使用Executors 创建常见的功能线程池
Executors为我们封装好了 4 种常见的功能线程池如下:
- 定长线程:FixedThreadPool
- 定时线程:ScheduledThreadPool
- 可缓存线程池:CachedThreadPool
- 单线程化线程池:SingleThreadExecutor
使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池,该方法创建的线程池的返回值类型均为 ExecutorService。
定长线程:FixedThreadPool:
源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
特点:定长线程池 核心线程数 == 最大线程数 ,即没有临时线程,且执行完毕会立刻回收,这种类型的线程池使用频率最高。
定时线程:ScheduledThreadPool:
源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
**加粗样式** **加粗样式** public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
特点:定时线程池的核心线程数量固定,虽然它的构造方法里面没有写最大线程的数量是多少,但是跟进查看源码可以知道,最大线程数量是等于 Integer.MAX_VALUE 的,工作队列是高度定制化的延迟阻塞队列DelayedWorkQueue,其实现原理和DelayQueue基本一样,核心数据结构是二叉最小堆的优先队列,队列满时会自动扩容,所以offer操作永远不会阻塞,maximumPoolSize也就用不上了,所以线程池中永远会保持至多有corePoolSize个工作线程正在运行。
可缓存线程池:CachedThreadPool:
源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
特点:可缓存线程池的核心线程数 = 0,最大线程数为 Integer.MAX_VALUE ,它会在执行闲置60s后回收,任务队列为不储存元素的阻塞队列。适合于并发不固定的短期的小任务。
单线程化线程池:SingleThreadExecutor:
源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
特点:单线程化线程池的核心线程数 == 最大线程数 == 1,执行完毕会立即回收,任务队列为链表结构的有界队列。