线程池
线程池是一种 “池化” 的线程使用模式,通过创建一定数量的线程,让这些线程处于就绪状态来提高系统响应速度,在线程使用完成后归还到线程池来达到重复利用的目标,从而降低系统资源的消耗。
池的好处
使用线程池,有如下优势
- 降低资源消耗
- 通过重复利用已创建的线程降低线程创建和销毁造成的消耗
- 提高响应速度
- 当任务到达时,任务可以不需要等到线程创建就能立即执行
- 提高线程的可管理性
- 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
- 提供更多更强大的功能
- 线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池
ScheduledThreadPoolExecutor
,就允许任务延期执行或定期执行
- 线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池
Executors
为了能更好的控制多线程,JDK 提供了一套 Executor
框架,其本质就是一个线程池,它的核心成员如下。
接口或类 | 说明 |
---|---|
Executor 接口 |
定义了一个接收 Runnable 对象的方法 executor |
ExecutorService 接口 |
一个比 Executor 使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回 Future 的方法 |
AbstractExecutorService 抽象类 |
ExecutorService 执行方法的默认实现 |
ScheduledExecutorService 接口 |
一个可定时调度任务的接口 |
ScheduledThreadPoolExecutor 类 |
ScheduledExecutorService 的实现,一个可定时调度任务的线程池 |
ThreadPoolExecutor 类 |
多用于创建线程池 |
常用方法
Executors
常用方法如下
newCachedThreadPool()
- 创建一个可缓存的线程池
CachedThreadPool
适用于并发执行大量短期耗时短的任务,或者负载较轻的服务器
newFiexedThreadPool(int nThreads)
- 创建固定数目线程的线程池
FiexedThreadPool
适用于负载略重但任务不是特别多的场景,为了合理利用资源需要限制线程数量的场景
newSingleThreadExecutor()
- 创建一个单线程化的
Executor
SingleThreadExecutor
适用于串行执行任务的场景,每个任务按顺序执行,不需要并发执行
- 创建一个单线程化的
newScheduledThreadPool(int corePoolSize)
- 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代
Timer
类 ScheduledThreadPool
是一个调度池,其实现了schedule
、scheduleAtFixedRate
、scheduleWithFixedDelay
三个方法,可以实现延迟执行、周期执行等操作
- 创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代
newSingleThreadScheduledExecutor()
- 创建一个
corePoolSize
为 1 的ScheduledThreadPoolExecutor
- 创建一个
newWorkStealingPool(int parallelism)
- 返回一个
ForkJoinPool
实例 ForkJoinPool
主要用于实现 “分而治之” 的算法,适合于计算密集型的任务
- 返回一个
避免使用Executors创建线程池
根据阿里《Java开发手册》,要避免使用 Executors
创建线程池,推荐使用 ThreadPoolExecutors
创建线程池。
Executors
创建的FiexedThreadPool
和SingleThreadPool
任务队列长度为Integer.MAX_VALUE
,可能会堆积大量的请求,从而导致 OOM;Executors
创建的CachedThreadPool
和ScheduledThreadPool
允许创建的线程数量为Integer.MAX_VALUE
,可能会创建大量的线程,从而导致 OOM。
ThreadPoolExecutor
Java 中,线程池的实现类是 ThreadPoolExecutor
,其构造函数如下。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,