线程池
主要控制运行线程的数量,将待处理的任务放入等待队列,创建线程执行任务,若超过最大线程池大小,等待其他任务执行完毕,再从队列中取出执行。
线程复用,控制最大并发数
线程池按以下行为执行任务
- 当线程数小于核心线程数时,创建线程。
- 当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
- 当线程数大于等于核心线程数,且任务队列已满
- 若线程数小于最大线程数,创建线程
- 若线程数等于最大线程数,抛出异常,拒绝任务
工具类Executors的API创建方式
1、newFixedThreadPool,
创建固定大小的线程池,超过最大任务数后会在等待队列等待
等待队列为LinkedBlockingQueue,默认大小最大为Integer最大(OOM)
2 、newSingleThreadExecutor
相当于newFix(1),问题也是队列大小最大Integer(OOM)
3、newCachedThreadPool
可缓存线程池,线程数不足时创建新线程,超过时回收旧线程。线程最大数量无限制(导致OOM), 因为可复用,所以可以减少系统开销,工作队列为SynchronousQueue
《阿里巴巴Java开发手册》的提示不容忽略:
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样
的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
正式编码中,推荐根据实际情况,使用new ThreadPoolExecutor来创建线程池
/**
* 使用给定的参数创建ThreadPoolExecutor.
*
* @param corePoolSize 核心线程池中的最大线程数
* @param maximumPoolSize 总线程池中的最大线程数 需大于等于1
* @param keepAliveTime 空闲线程的存活时间
* @param unit keepAliveTime的单位
* @param workQueue 任务队列, 保存已经提交但尚未被执行的线程
* @param threadFactory 线程创建工厂
* @param handler 拒绝策略 (当任务太多导致工作队列满时的处理策略)
*/
new ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
RejectedExecutionHandler 拒绝策略四种
在池中线程到达最大数量后,且任务队列也满了,则会调用RejectedExecutionHandler对新任务进行处理。
1、new ThreadPoolExecutor.AbortPolicy(); 为默认策略
直接抛出异常。源码如下
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException();
}
2、new ThreadPoolExecutor.CallerRunsPolicy();
在当前调用execute(Runnable r)的线程中直接调用run方法,异步改同步,由调用者线程处理。源码如下
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
3、new ThreadPoolExecutor.DiscardOldestPolicy();
丢弃最早进入队列的任务,队列中加入新任务,源码如下
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
4、new ThreadPoolExecutor.DiscardPolicy();
直接丢弃新任务,不处理,源码如下
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
生产中如何设置线程池各个参数?
我实际中用到线程池但是并发量不多,一分钟来3-5个任务,每个任务正常执行近10秒,设置了核4 最大8,考虑中间执行可能接口超时,超过10s,队列设置了15的参数
看了看别的博客,说的公式什么的,我理解不深,感觉一丝丝不得劲,先不写了,再研究研究