为什么要用线程池?核心参数有哪些
作用
- 降低资源消耗;提高线程利用率,降低创建和销毁线程的消耗。
- 提高响应速度;任务来了直接有线程可用可执行,而不是先创建线程,再执行。
- 提高线程的可管理;线程是稀缺资源,使用线程池可用统一分配调优监控。
线程池创建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
核心参数
corePoolSize:核心线程最大数量,即线程池中常驻线程的最大数量。线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程;如果超过了corePoolSize则新建的是非核心线程。
maximumPoolSize:线程池中运行的最大线程数,包括核心线程和非核心线程。
keepAliveTime:线程池中空闲线程所存活的最长时间(仅适用于非核心线程)。
unit:表示超出核心线程数之外的线程的空闲存活时间,也就是核心线程不会消除,但是超出核心线程数的部分线程如果空闲一定的时间则会被消除,可以通过keepAliveTime来设置空闲时间。
workQueue:用来存放任务的阻塞队列,假设我们现在核心线程都被使用,还有任务进来则全部放入队列,直到整个队列被放满但再持续进入则会创建新的线程。
ThreadFactory:实际上是一个线程工厂,用来生产线程执行任务,我们可以选择使用默认的创建工厂,产生的线程都在同一个组内,拥有相同的优先级,且都不是守护线程。当然我们也可以选择自定义线程工厂,一般会根据业务来制定不同的线程工厂。
Handler:任务拒绝策略,有两种情况,第一种是当我们调用shutdown等方法关闭线程池后,这时候即使线程池内部还有没执行完的任务正在执行,但是由于线程池已经关闭,我们再继续想线程池提交任务就会遭到拒绝,另一种情况就是当达到最大线程数,线程池已经没有能力继续处理新提交的任务时,这时也就会拒绝。
执行流程图
- 判断线程池中的核心线程数是否已经到达corePoolSize,没有则创建一个核心线程执行任务。
- 若核心线程数已经到达corePoolSize,判断阻塞队列workQueque是否已满,如果没满,则将新任务加入阻塞队列。如果已满,判断线程池中的线程数是否到达maximumPoolSize,如果没有,则新建一个非核心线程执行任务,如果到达阀值,则执行线程池饱和策略。
线程池饱和策略
- AbortPolicy:直接抛出一个异常阻止系统正常运行,默认策略
- DiscardPolicy:直接丢弃任务,不予任何处理也不抛异常(如果允许任务丢失,建议此方案)
- DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
- CallerRunsPolicy:调用者运行一种调节机制,该策略既不会抛弃任务也不会抛异常,而是将某些任务回退到调用者,从而降低新任务的流量。