创建线程池的几种方式&& 核心参数详解
概述
通过线程池来管理线程的方式,优势十分明显:
- 线程生命周期的开销非常高(创建与销毁)
- 线程运行占用系统资源(当活跃线程数大于系统CPU数量时,大量处于就绪状态的线程消耗了系统资源)
- 通过集中管理线程,确保系统稳定性(线程创建本身需要占用系统资源,大量创建新线程可能导致OOM )
综合以上几点,一般在生产环境严禁不通过线程池的方式来创建线程;
Executor及常见子类UML图
核心参数详解
int corePoolSize
- 线程池中活跃的线程数目
int maximumPoolSize
- 线程池中最大的线程数目
long keepAliveTime
- 线程最大空闲时间
TimeUnit unit
- keepAliveTime的单位
- TimeUnit.NANOSECONDS 纳秒
- TimeUnit.MICROSECONDS 微秒
- TimeUnit.MILLISECONDS 毫秒
- TimeUnit.SECONDS 秒
- TimeUnit.MINUTES
- TimeUnit.HOURS
- TimeUnit.DAYS
BlockingQueue workQueue
- 当通过execute方法提交的任务,在被执行前的临时保存队列
ThreadFactory threadFactory
- 执行器创建一个新线程的工厂类
RejectedExecutionHandler handler
- 当前工作队列已满时,新任务提交的拒绝策略
- CallerRunsPolicy:将任务交由当前提交的线程执行
- AbortPolicy:通过抛异常的方式,拒绝提交
- DiscardPolicy:不抛异常,拒绝提交
- DiscardOldestPolicy:抛弃最开始提交的(队列头部)的一条任务,将此任务压入队尾
常用创建线程池方式
通过构造器,自定义线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10,
20,
0,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(50),
new ThreadPoolExecutor.DiscardOldestPolicy());
Executors工具类创建线程池
public class MyExecutor {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10,
20,
0,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(50),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
// 创建只有一个线程的线程池
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
// 创建一个无限大的线程池,
// 当有新任务到达时,一定需要一个线程来执行
// 适用于线程执行时间短的场景
ExecutorService executorService2 = Executors.newCachedThreadPool();
// 创建固定线程数量的线程池
// corePoolSize = maximunPoolSize
ExecutorService executorService3 = Executors.newFixedThreadPool(20);
// 创建需要任务延迟执行的线程池
ExecutorService executorService4 = Executors.newScheduledThreadPool(20);
}
}