一、线程池的作用
《Java 并发编程的艺术》提到的使用线程池的好处:
- 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。
- 提高线程的可管理性。 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
二、线程池如何使用
首先看一下线程池的公共接口和常用的两个实现类
- 接口ExecutorService的实现类
- ThreadPoolExecutor: 普通线程池
- ScheduledThreadPoolExecutor: 定时调度任务线程池
- 更具体的实现类:
- FixedThreadPool:线程数固定的线程池;
- CachedThreadPool:线程数根据任务动态调整的线程池;
- SingleThreadExecutor:仅单线程执行的线程池。
============线程池的定义============
// 1.创建固定大小的线程池,无救急线程
ExecutorService executor = newFixedThreadPool(3);
============线程池的任务执行============
Ruuable task = ()-> {//执行的任务};
executor.submit(task1);
三、线程池的7个参数
- 构造方法的7个参数(最全)
- corePoolSize 核心线程数目 (最多保留的线程数)
- maximumPoolSize 最大线程数目(核心线程数加上救急线程数)
- keepAliveTime 救急线程的生存时间(核心线程没有生存时间这个东西,核心线程会一直运行)
- unit 时间单位 - 针对救急线程
- workQueue 阻塞队列
- threadFactory 线程工厂 - 可以为线程创建时起个好名字
- handler 拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler){
}
下面结合线程池的运行流程,来详细讲解一下这7个参数的作用
四、线程池的运行流程
- 线程池的使用流程
- 1.线程池刚开始时没有线程,当一个任务提交给线程池后,线程工厂会创建一个新线程来执行任务
- 2.当线程数达到核心线程数并没有线程空闲,这时再加入任务,新加的任务会被加入到等待队列中排队,直到有空闲的线程
- 3.如果队列先择了有界队列,那么任务超过了队列大小时,会创建救急线程(最大线程数-核心线程数)【并且会插队,图中的task8】
- 4.如果线程数到达最大线程数时,这时会执行拒绝策略,拒绝策略jdk提供了4种实现
- ThreadPoolExecutor.AbortPolicy让调用者抛出 RejectedExecutionException 异常,这是默认策略
- ThreadPoolExecutor.CallerRunsPolicy 让调用者运行任务,即主线程自己run
- ThreadPoolExecutor.DiscardPolicy 放弃本次任务
- ThreadPoolExecutor.DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之
- 5.当高峰期过去后,超过核心线程数的救急线程,如果一段时间内没有任务做,会释放掉节省资源,这个时间由存活时间和时间单位控制