What?
1. 简介
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
本文主要介绍j.u.c.ThreadPoolExecutor线程池的使用及源码分析
2. 成员
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:队列中任务等待执行时间
- unit:队列中任务等待执行时间单位
- workQueue:等待执行任务的队列
- threadFactory:新线程的创建方式
- handler:队列满了且大于最大线程数后任务的拒绝策略
这7个参数在本文后面源码分析中会详细介绍
Why?
- 降低资源(利用重复机制,降低创建和销毁线程的次数)
- 提高执行效率(当任务到达时,不需要等待线程的创建就能立马执行)
- 提高线程可管理性(线程池是稀缺资源,使用线程池可以限制创建,充分利用系统资源,提高系统的稳定性,进行统一的分配,调优和监控)
若想合理使用线程池,必须了解线程池的核心参数
How?
1. Executors创建线程池
方法 | 说明 |
---|---|
newFixedThreadPool(int nThreads) | 创建固定线程数的线程池 |
newCachedThreadPool() | 创建线程数不受上限的线程池,任何提交的任务都将立即执行 |
newSingleThreadExecutor() | 创建一个线程的线程池 |
newScheduledThreadPool(int corePoolSize) | 创建核心线程数为corePoolSize,可执行定时任务的线程池 |
newSingleThreadScheduledExecutor() | 创建一个线程的定时线程池 |
不推荐,阿里巴巴开发手册:【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
· newFixedThreadPool()源码如下
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
没有指定等待任务队列长度,可能会堆积大量的请求,从而导致 OOM。
· newCachedThreadPool()源码如下
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
最大线程数为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM
2. ThreadPoolExecutor核心参数详解
- corePoolSize:创建真正的线程数,执行任务和等待队列中的任务,当线程数小于该值时,优先执行新建的任务
- maximumPoolSize:线程池中运行的最大线程池
- keepAliveTime:当线程数大于核心线程数时,多余线程等待新任务的最长时间,若超时,则线程退出
- unit:队列任务等待时间的单位
- workQueue:当线程数大于核心线程数时,用来缓存未执行的任务,队列会一直持有任务直到有线程开始执行它
- threadFactory:通过工厂创建自定义名字的线程
- handler:当线程数大于最大线程数且队列已满时,采取拒绝策略处理新任务
· 常用堵塞队列
堵塞队列 | 说明 |
---|---|
ArrayBlockingQueue | 基于数组结构的堵塞队列,可自定义队列长度 |
LinkedBlockingQueue | 基于链表的堵塞队列,可自定义队列长度 |
SynchronousQueue | 同步队列,该队列不存储元素,每个插入操作必须等待另一个线程调用移除操作,否则插入操作会一直被阻塞 |
· ThreadPoolExecutor提供四种拒绝策略
拒绝策略 | 说明 |
---|---|
AbortPolicy | 直接丢弃新任务,并抛出 RejectedExecutionException,线程池默认策略 |
DiscardPolicy | 无任何处理,直接丢弃新任务 |
DiscardOldestPolicy | 丢弃队首任务,并执行新任务 |
CallerRunsPolicy | 若线程没有退出时,由当前线程执行新任务 |