1. 线程池是什么
场景:麦当劳/肯德基的点餐取餐流程
传统方式(没有线程池):
每来一个顾客,经理就现招一个临时工,从培训到上岗要5分钟
顾客取完餐,这个临时工立刻被解雇
下一个顾客来,又要重新招聘培训
高峰期时,经理一直在招聘和解雇,手忙脚乱
使用线程池的方式:
预先准备:经理早上就培训好3个固定员工站在取餐窗口后
顾客点餐:顾客点完餐拿到号码,在取餐区等待
分配任务:有空闲窗口时,叫号员喊:"xxx号请到2号窗口"
高效处理:窗口员工快速配餐,完成后立即服务下一个顾客
灵活调整:
中午人多时,经理临时增加1个窗口(扩大线程池)
下午人少时,让1个员工去休息(缩小线程池)
线程池最大的好处就是减少每次启动、销毁线程的损耗。
2.线程池的核心参数
java
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略处理器
)
2.1 corePoolSize(核心线程数)
-
线程池中保持存活的最小线程数量
-
即使这些线程处于空闲状态也不会被销毁
-
除非设置
allowCoreThreadTimeOut为true
2.2 maximumPoolSize(最大线程数)
-
线程池允许创建的最大线程数量
-
当工作队列满时,线程池会创建新线程,直到达到此限制
2.3 keepAliveTime(线程存活时间)
-
非核心线程的空闲存活时间
-
超过此时间,空闲的非核心线程将被终止
2.4 workQueue(工作队列)
-
用于存放等待执行的任务的阻塞队列
-
常见类型:
-
LinkedBlockingQueue:无界队列(默认)
-
ArrayBlockingQueue:有界队列
-
SynchronousQueue:不存储元素的队列
-
PriorityBlockingQueue:优先级队列
-
2.5 ThreadFactory(线程工厂)
-
用于创建新线程的工厂
-
可以自定义线程名称、优先级、守护状态等
2.6 RejectedExecutionHandler(拒绝策略)
-
当线程池和工作队列都满时,对新任务的处理策略
-
四种内置策略:
-
AbortPolicy(默认):抛出RejectedExecutionException异常
-
CallerRunsPolicy:由调用线程执行该任务
-
DiscardPolicy:直接丢弃任务
-
DiscardOldestPolicy:丢弃队列中最旧的任务,然后重试
-
3. Executors 创建线程池的几种方式
- newFixedThreadPool: 创建固定线程数的线程池
java
//创建固定大小为5的线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
// 特点:
// - 核心线程数 = 最大线程数 = 指定参数
// - 使用无界LinkedBlockingQueue
// - 适用于负载较重的服务器,限制线程数量
- newCachedThreadPool: 创建线程数目动态增长的线程池.
java
//创建可缓存的线程池
ExecutorService cashedThreadPool = Executors.newCachedThreadPool();
// 特点:
// - 核心线程数 = 0,最大线程数 = Integer.MAX_VALUE
// - 使用SynchronousQueue(不存储元素)
// - 空闲线程60秒后终止
// - 适用于执行大量短期异步任务
- newSingleThreadExecutor: 创建只包含单个线程的线程池.
java
//创建单线程的线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 特点:
// - 只有一个工作线程
// - 保证任务顺序执行
// - 适用于需要顺序执行任务的场景
// - 使用无界LinkedBlockingQueue
//"无界"的具体表现:
// 1. 默认构造函数:Integer.MAX_VALUE 容量(约21亿)
// 2. 可指定初始容量,但超过后会继续接受新元素
// 3. 实际上受JVM堆内存限制
- newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.
java
//创建可定时执行的线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
// 常用方法:
// 延迟执行
scheduledThreadPool.schedule(task,10, TimeUnit.SECONDS);
/*
1."task":要执行的任务
2."10":延迟时间
3."TimeUnit.SECONDS":时间单位,秒
*/
//固定频率执行
scheduledThreadPool.scheduleAtFixedRate(task,5,2,TimeUnit.SECONDS);
/*
1."task":要执行的任务
2."5":初始延迟时间,即从现在开始等待5秒后,第一次执行任务
3."2":任务执行的周期,即每隔2秒执行一次任务
4."TimeUnit.SECONDS":时间单位,秒
*/
//固定延迟执行
scheduledThreadPool.scheduleWithFixedDelay(task,5,2,TimeUnit.SECONDS);
/*
1."task":要执行的任务
2."5":初始延迟时间,即从现在开始等待5秒后,第一次执行任务
3."2":任务执行结束到下一次任务开始之间的延迟时间,即每次任务完成后,等待2秒再开始下一次
4."TimeUnit.SECONDS":时间单位,秒
*/
Executors 本质上是 ThreadPoolExecutor 类的封装.