真实面经题目 · 原创解析
Java 线程池有哪些核心参数?
Java 线程池的核心参数来自 ThreadPoolExecutor:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、RejectedExecutionHandler。真正要掌握的是它们如何共同决定线程创建、任务排队、扩容、回收和拒绝策略。
真实面经题目 · 原创解析
Java 线程池的核心参数来自 ThreadPoolExecutor:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、RejectedExecutionHandler。真正要掌握的是它们如何共同决定线程创建、任务排队、扩容、回收和拒绝策略。
回答线程池参数不能只背名称,要说明任务提交流程。新任务进来时,如果运行线程数小于 corePoolSize,优先创建核心线程;否则尝试放入 workQueue;如果队列满且线程数小于 maximumPoolSize,再创建非核心线程;如果仍无法处理,就走拒绝策略。keepAliveTime 控制空闲非核心线程的回收,也可以通过配置作用于核心线程。threadFactory 用来定制线程名、优先级、异常处理等,RejectedExecutionHandler 决定过载时是抛异常、调用者执行、丢弃还是丢弃最旧任务。
ThreadPoolExecutor 的核心构造参数包括 corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory 和 RejectedExecutionHandler。它们不是孤立配置,而是共同描述线程池的容量边界和过载行为。corePoolSize 决定常驻线程规模,maximumPoolSize 决定峰值上限,队列决定缓冲能力,拒绝策略决定系统承压后的失败方式。
任务提交后,线程池先看当前工作线程数是否小于 corePoolSize,如果是就创建线程执行任务;如果核心线程已满,尝试把任务放入 workQueue;如果队列也满,再判断是否可以创建线程直到 maximumPoolSize;如果线程数已到最大仍无法接收,就执行拒绝策略。理解这个顺序比死记参数更重要,因为它决定参数调优方向。
workQueue 对线程池行为影响很大。无界队列会让任务大量排队,maximumPoolSize 可能几乎不生效,风险是内存压力和响应时间变长;有界队列能限制积压,促使线程池扩容或触发拒绝,适合保护系统;同步移交队列不存储任务,通常要求快速创建线程或及时拒绝。队列选择本质上是在吞吐、延迟和资源保护之间取舍。
keepAliveTime 和 unit 控制空闲线程存活时间,默认主要影响超过核心数的非核心线程。当任务高峰过去后,非核心线程空闲超过该时间会被回收,降低资源占用。若启用核心线程超时,核心线程也可能被回收。这个参数不能孤立设置,必须结合任务波峰波谷、线程创建成本、响应延迟要求来决定。
拒绝策略是线程池容量耗尽时的最后防线。AbortPolicy 会抛异常,适合让调用方感知失败;CallerRunsPolicy 让提交任务的线程自己执行,能形成反压但会拖慢调用链;DiscardPolicy 静默丢弃,风险较高;DiscardOldestPolicy 丢弃队列中最旧任务再尝试提交。生产系统常会自定义策略,记录日志、打点、降级或返回明确错误。
因为核心线程满后任务会一直进入无界队列,队列不满就不会走创建非核心线程的分支,因此最大线程数很难被触发。
要看任务类型。CPU 密集型通常接近 CPU 核数,IO 密集型可以更高,但还要结合外部资源容量、延迟目标和压测结果。
它让提交任务的线程执行被拒绝的任务,相当于把压力反推给调用方,降低提交速度,但可能拉长上游请求耗时。
最怕只增大线程数和队列长度。这样可能掩盖瓶颈,造成更高内存占用、更频繁上下文切换和更长尾延迟。