转自:https://blog.csdn.net/zzti_erlie/article/details/108552109
线程池的各种参数
面试的时候最常问的就是线程池的各种参数的含义,和线程池的整个运行流程,这个一定要会
ThreadPoolExecutor 一 共有 4 个构造函数,但最后调用的都是如下构造函数
|参数|含义|
|—-|—-|
|corePoolSize|核心线程池大小|
|maximumPoolSize|线程池最大容量大小|
|keepAliveTime|线程池空闲时,线程存活的时间|
|TimeUnit|线程活动保持时间的单位|
|BlockingQueue<Runnable>
|任务队列,用于保存等待执行的任务的阻塞队列|
|ThreadFactory|用于设置线程的工厂|
|RejectedExecutionHandler|饱和策略|
来类比学习一下这些参数,我们把线程池类比为项目组,线程是这个公司的成员
- corePoolSize:线程池中最少的线程数,一个项目组总得有 corePoolSize 人坚守阵地,都是签订劳动合同了,不能随便撤。
- maximumPoolSize:当项目很忙时,就得加人,请其他项目组的人来帮忙。但是公司空间有限,最多只能加到 maximumPoolSize 个人。当项目闲了,就得撤人了,最多能撤到 corePoolSize 个人
- keepAliveTime & unit:上面提到项目根据忙闲来增减人员,那在编程世界里,如何定义忙和闲呢?如果一个线程在 keepAliveTime(时间数字)* unit(时间单位)时间内都没有执行任务,说明这个线程很闲。如果此时线程数大于 corePoolSize,这个线程就要被回收了
- workQueue:就是任务队列
- threadFactory:自定义如果创建线程,例如给线程指定一个有意义的名字
- handler:workQueue满了(排期满了),再提交任务,该怎么处理呢?这个就是处理策略,线程池提供了4种策略,你也可以实现RejectedExecutionHandler接口来自定义策略
类 | 策略 |
---|---|
AbortPolicy | 丢弃任务,抛运行时异常(默认的处理策略) |
CallerRunsPolicy | 执行任务 |
DiscardPolicy | 忽视,什么都不会发生 |
DiscardOldestPolicy | 丢弃队列里最近的一个任务,并执行当前任务 |
线程池的工作流程
可以参照一下源码理解一下下面的流程
- 线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行他们。
- 当调用 execute() 方法添加一个任务时,线程池会做如下判断:
- 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务
- 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列
- 如果这时候队列满了,而且正在运行的线程数量小于 maximunPoolSize,那么还是要创建非核心线程立刻运行这个任务
- 如果队列满了,而且正在运行的线程数量大于或等于 maximunPoolSize,那么线程池会抛出 RejectedExecutionException
- 当一个线程完成任务时,它会从队列中取下一个任务来执行
- 当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小
可以用如下图来表示整体流程