Java线程池的了解
1、线程池
线程池是一种 “池化” 的线程使用模式,通过创建一定数量的线程,让这些线程处于就绪状态来提高系统响应速度,在线程使用完成后归还到线程池来达到重复利用的目标,从而降低系统资源的消耗。
1.1、池的好处
使用线程池,有如下优势
降低资源消耗
通过重复利用已创建的线程降低线程创建和销毁造成的消耗
提高响应速度
当任务到达时,任务可以不需要等到线程创建就能立即执行
提高线程的可管理性
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控
提供更多更强大的功能
线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池
ScheduledThreadPoolExecutor
,就允许任务延期执行或定期执行
1.2、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。
1.3、ThreadPoolExecutor
Java 中,线程池的实现类是 ThreadPoolExecutor
,其构造函数如下。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit timeUnit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
:线程池核心线程数maximumPoolSize
:线程池所能容纳的最大线程数keepAliveTime
:线程闲置存活时长timeUnit
:线程闲置存活时长的时间单位,如TimeUnit.MILLISECONDS
、TimeUnit.SECONDS
blockingQueue
:任务队列,常用的任务队列包括ArrayBlockingQueue
:一个数组实现的有界阻塞队列,此队列按照 FIFO 的原则对元素进行排序,支持公平访问队列LinkedBlockingQueue
:一个由链表结构组成的可选有界阻塞队列,如果不指定大小,则使用Integer.MAX_VALUE
作为队列大小,按照 FIFO 的原则对元素进行排序PriorityBlockingQueue
:一个支持优先级排序的无界阻塞队列,默认情况下采用自然顺序排列,也可以指定Comparator
DelayQueue
:一个支持延时获取元素的无界阻塞队列,创建元素时可以指定多久以后才能从队列中获取当前元素,常用于缓存系统设计与定时任务调度等SynchronousQueue
:一个不存储元素的阻塞队列,存入操作必须等待获取操作,反之亦然LinkedTransferQueue
:一个由链表结构组成的无界阻塞队列,与LinkedBlockingQueue
相比多了transfer
和tryTranfer
方法,该方法在有消费者等待接收元素时会立即将元素传递给消费者LinkedBlockingDeque
:一个由链表结构组成的双端阻塞队列,可以从队列的两端插入和删除元素
threadFactory
:线程工厂,用于指定为线程池创建新线程的方式,threadFactory
可以设置线程名称、线程组、优先级等参数,如通过 Google 工具包可以设置线程池里的线程名,代码如下。
newThreadFactoryBuilder().setNameFormat("general-detail-batch-%d").build();
RejectedExecutionHandler
:拒绝策略,常见的拒绝策略包括ThreadPoolExecutor.AbortPolicy
:默认策略,当任务队列满时抛出RejectedExecutionException
异常ThreadPoolExecutor.DiscardPolicy
:丢弃掉不能执行的新任务,不抛任何异常ThreadPoolExecutor.CallerRunsPolicy
:当任务队列满时使用调用者的线程直接执行该任务ThreadPoolExecutor.DiscardOldestPolicy
:当任务队列满时丢弃阻塞队列头部的任务(即最老的任务),然后添加当前任务
todo...