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()创建一个单线程化的
ExecutorSingleThreadExecutor适用于串行执行任务的场景,每个任务按顺序执行,不需要并发执行
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.SECONDSblockingQueue:任务队列,常用的任务队列包括ArrayBlockingQueue:一个数组实现的有界阻塞队列,此队列按照 FIFO 的原则对元素进行排序,支持公平访问队列LinkedBlockingQueue:一个由链表结构组成的可选有界阻塞队列,如果不指定大小,则使用Integer.MAX_VALUE作为队列大小,按照 FIFO 的原则对元素进行排序PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列,默认情况下采用自然顺序排列,也可以指定ComparatorDelayQueue:一个支持延时获取元素的无界阻塞队列,创建元素时可以指定多久以后才能从队列中获取当前元素,常用于缓存系统设计与定时任务调度等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...