(1)什么是线程池?
在内存中缓存一些线程对象的地方
(2)为什么要使用线程池?
1. 线程的创建和销毁比较耗费资源, 若频繁得创建和销毁将损失一部分的性能
2. 随着线程数的增加,CPU的上下文的切换将变得频繁,上下切换也是相对好耗时,一旦切换变得频繁,那么在单位时间内,CPU执
行程序的逻辑时间就相对变短了,从而损失性能
3. 线程对象其实是可以反复被利用的
(3)何时考虑使用线程池:
特别是需要有很多并发任务执行且这种任务短的时候我们就需要考虑是否要利用线程池来处理并发任务
(4)线程池对线程的管理:
1. 状态:
空闲(空闲时长):当线程对象没有执行任务时,线程池会标记该线程对象为空闲状态,并记录该线程对象的空闲时长
忙碌:当线程对象开始执行任务时,线程池会标记该线程对象为忙碌状态,并清空空闲时长
2. 数量
新建线程:当池中线程不够用时, 可能会去新建线程对象;到底是否会新建看线程池的配置策略
一般情况:
当池中线程数尚未到底某个阀值时,会新建线程对象去处理任务;
当池中线程数已达到某个阀值时,则不会创建线程对象,而是将这个任务放入任务队列中,等待其他线程空闲后再对队列中的任务进行处
理
销毁线程:当池中线程空闲太长, 可能会去销毁哪些空闲太长的线程对象;到底是否会销毁看线程池的配置策略
一般情况:
当池中线程数尚未达到某个阀值时,不销毁空闲超时的线程;
当池中线程数已超过某个阀值时,将销毁空闲超时的线程,直到到达某个阀值
3. 任务等待队列
放任务:当前线程不够用时,又不创建新线程时,将该任务放入等待队列中
消费任务:从等待队列中取出任务并执行
(5)在Java如何使用线程池
Executor(接口): 执行器
|- ExecutorService(接口): 执行服务
|- ThreadPoolExecutor(是一个实现类): 线程池,用于执行各种任务
|- ScheduledThreadPoolExecutor: 线程池,用于周期性执行各种任务
Executors工具类:提供了几个静态方法来构造内置的线程池对象
newSingleThreadExecutor():创建只有一个线程的线程池, 采用无界队列
newFixedThreadPool(int nThreads):创建一个具有指定个数的线程的线程池, 采用无界队列
newCachedThreadPool():创建一个无界线程池(符合任务多,时间短的情况)
newScheduledThreadPool(int corePoolSize)创建一个可延迟或定期执行任务的线程池,核心线程数量为:corePoolSize
采用无界队列
ThreadPoolExecutor类:用该类来定制我们自己的线程池(即上面的Executors构造方法任然满足不了我们的需要)
构造方法:
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue
)
corePoolSize参数: 配置该线程池的核心线程数量
当有新任务时:
若池中线程数量未达corePoolSize,则新建线程对象来运行该任务而不管当前池中是否存在空闲线程;
若池中线程数量已达corePoolSize,则将任务放入等待队列中
maximumPoolSize参数: 配置该线程池的最大线程数量
当有新任务时:
若池中线程数量未达maximumPoolSize且等待队列满了,则新建线程对象来处理任务
若池中线程数量已达maximumPoolSize, 按照拒绝任务策略对任务进行处理(默认处理策略:丢弃该任务并抛出异常)
keepAliveTime参数: 配置该线程池中线程的空闲超时时长
当池中线程数量大于corePoolSize时,将销毁空闲超时的线程
当池中线程数量小于等于corePoolSize时,将不进行回收
unit参数: 指定超时时长的单位
workQueue: 指定当前线程池所采用的等待队列
若采用无界队列LinkedBlockingQueue则maximumPoolSize参数将失去意义
只有采用有界队列ArrayBlockingQueue是maximumPoolSize才有意义