ThreadPoolExecutor 的七个核心构造参数分别是什么?
Java 中 ThreadPoolExecutor 的七个核心构造参数是理解和使用 Java 线程池的关键,这也是 Java 面试中极其高频的考点。
以下是这七个核心参数的详细解释:
1. corePoolSize(核心线程数)
- 含义:线程池中长期维持的、即使处于空闲状态也不会被销毁的线程数量(除非设置了
allowCoreThreadTimeOut = true)。 - 作用:当有新任务提交时,如果当前运行的线程数小于
corePoolSize,线程池会创建一个新线程来执行任务,即使池中有其他空闲的核心线程。
2. maximumPoolSize(最大线程数)
- 含义:线程池允许创建的最大线程数量。
- 作用:当核心线程数已满,并且工作队列(workQueue)也已经满了的情况下,如果还有新任务提交,线程池就会继续创建新的非核心线程来处理任务,直到线程总数达到
maximumPoolSize。
3. keepAliveTime(空闲线程存活时间)
- 含义:当线程池中的线程数量超过
corePoolSize时,这些多余的空闲线程(非核心线程)在被销毁之前等待新任务的最长时间。 - 作用:用于控制非核心线程的生命周期,避免系统资源的浪费。
4. unit(时间单位)
- 含义:
keepAliveTime参数的时间单位。 - 常用值:
TimeUnit.SECONDS(秒)、TimeUnit.MILLISECONDS(毫秒)、TimeUnit.MINUTES(分钟)等。
5. workQueue(工作/任务队列)
- 含义:用于保存等待执行的任务的阻塞队列。
- 作用:当所有核心线程都在工作时,新提交的任务会被放入这个队列中排队等待。常见的队列有:
ArrayBlockingQueue:基于数组的有界阻塞队列。LinkedBlockingQueue:基于链表的阻塞队列(默认容量为Integer.MAX_VALUE,常被称为无界队列,但强烈建议指定容量)。SynchronousQueue:不存储元素的阻塞队列(每个插入操作必须等待另一个线程的移除操作),通常配合较大的最大线程数使用(如CachedThreadPool)。PriorityBlockingQueue:具有优先级的无界阻塞队列。
6. threadFactory(线程工厂)
- 含义:用于创建新线程的工厂。
- 作用:通过自定义线程工厂,可以给线程池中的线程设置有意义的名字、设置是否为守护线程、设置线程优先级等。这在排查线上问题(如打印日志、查看 Dump 文件)时非常有用。默认使用
Executors.defaultThreadFactory()。
7. handler(拒绝策略/饱和策略)
- 含义:当线程池和工作队列都已经达到上限(即线程数等于
maximumPoolSize且workQueue已满),无法再接受新任务时,所采取的处理策略。 - 内置的四种策略:
AbortPolicy(默认):直接抛出RejectedExecutionException异常,阻止系统正常运行。CallerRunsPolicy:将任务回退给调用者,由提交任务的当前线程(通常是主线程)来直接执行该任务。这会降低新任务的提交速度。DiscardPolicy:直接静默丢弃新提交的任务,不抛出异常。DiscardOldestPolicy:丢弃队列中最老的一个任务(即排在队首、马上要被执行的任务),然后尝试重新提交当前任务。
💡 核心参数的联动执行流程(重要)
为了彻底掌握这 7 个参数,必须理解它们是如何配合工作的。当一个新任务提交到线程池时,处理流程如下:
- 判断核心线程:如果当前运行的线程数
< corePoolSize,立即创建新线程执行任务。 - 判断工作队列:如果当前运行的线程数
>= corePoolSize,将任务放入workQueue中等待。 - 判断最大线程数:如果
workQueue已满,且当前运行的线程数< maximumPoolSize,创建非核心线程执行任务。 - 执行拒绝策略:如果
workQueue已满,且运行的线程数>= maximumPoolSize,则触发handler(拒绝策略)处理该任务。