致敬读者
博主相关
文章前言
Java高并发线程池的面试核心内容。主要内容如下:
接下来,详细讲解Java高并发线程池的相关面试内容。
ScheduledThreadPool
)、顺序执行(SingleThreadExecutor
)等高级功能。以下表格总结了线程池的核心配置参数及其作用:
参数 | 作用 | 典型值/示例 |
---|---|---|
corePoolSize |
核心线程数,即使空闲也不会销毁 | CPU密集型:N+1 IO密集型:2N |
maximumPoolSize |
最大线程数(含核心线程) | 建议设置上限避免OOM |
keepAliveTime |
非核心线程空闲存活时间 | 配合TimeUnit.SECONDS 使用 |
workQueue |
任务存储队列 | LinkedBlockingQueue (无界)ArrayBlockingQueue (有界)SynchronousQueue (直接传递) |
threadFactory |
线程创建工厂(可定制线程名、优先级) | Executors.defaultThreadFactory() |
handler |
拒绝策略(当队列和线程池全满时触发) | AbortPolicy (抛异常)CallerRunsPolicy (调用者执行) |
参数协同逻辑:
corePoolSize
:立即创建新线程执行。corePoolSize
:任务进入workQueue
排队。maximumPoolSize
:创建非核心线程执行。maximumPoolSize
:触发拒绝策略。execute()
或submit()
提交任务。corePoolSize
→ 创建新线程执行。corePoolSize
→ 任务入队。maximumPoolSize
)。keepAliveTime
后被销毁。通过Executors工具类可创建四种常用线程池:
线程池类型 | 核心参数 | 队列类型 | 特点 | 风险 |
---|---|---|---|---|
FixedThreadPool |
core=max,keepAlive=0 | LinkedBlockingQueue (无界) |
固定线程数,适用于稳定并发 | 无界队列可能导致OOM |
CachedThreadPool |
core=0,max=Integer.MAX_VALUE | SynchronousQueue |
自动扩缩容,适合短时任务 | 线程数无上限可能耗尽资源 |
SingleThreadExecutor |
core=max=1 | LinkedBlockingQueue (无界) |
单线程顺序执行 | 无界队列可能导致OOM |
ScheduledThreadPool |
core可指定,max=Integer.MAX_VALUE | DelayedWorkQueue |
支持定时/周期性任务 | 任务堆积可能OOM |
⚠️ 阿里规约警示:
CachedThreadPool
和FixedThreadPool
因可能导致OOM,生产环境建议手动配置ThreadPoolExecutor
。
ArrayBlockingQueue
:数组实现的有界队列,FIFO排序,需指定容量。适用场景:需严格控制资源消耗的场景。LinkedBlockingQueue
:链表实现,默认无界(可设容量)。风险:任务堆积可能导致OOM(FixedThreadPool
和SingleThreadExecutor
默认使用)。SynchronousQueue
:不存储元素,插入操作需等待移除。特点:CachedThreadPool
使用,直接传递任务。PriorityBlockingQueue
:优先级排序的无界队列,任务需实现Comparable
。DelayedWorkQueue
:延迟队列(ScheduledThreadPool
使用),按到期时间排序。当队列满且线程数达上限时触发:
AbortPolicy
(默认):抛出RejectedExecutionException
,中断任务提交。DiscardPolicy
:静默丢弃新任务,无任何通知。DiscardOldestPolicy
:丢弃队列头部的旧任务,重试提交新任务。CallerRunsPolicy
:由提交任务的线程直接执行该任务,避免任务丢失。建议:生产环境推荐自定义策略(如记录日志、降级处理、持久化任务)。
线程池通过5种状态管理生命周期:
shutdown()
触发)。shutdownNow()
触发)。terminated()
钩子执行完毕)。ArrayBlockingQueue
)。AbortPolicy
,日志上报用DiscardPolicy
)。线程池执行任务有几种提交方式?
execute()
:提交Runnable
,无返回值。submit()
:提交Callable
或Runnable
,返回Future
对象(可获取结果或异常)。非核心线程何时被销毁?
当线程空闲时间超过keepAliveTime
,且当前线程数 > corePoolSize
时触发销毁。
如何优雅关闭线程池?
shutdown()
:等待存量任务执行完毕。shutdownNow()
:尝试中断所有任务,返回未执行的任务列表。为什么volatile
不能保证线程池安全?
volatile
仅保证可见性和有序性,但线程池任务需保证原子性(如ctl
状态控制需通过CAS操作)。
核心线程能否被回收?
默认不被回收,但可通过allowCoreThreadTimeOut(true)
设置核心线程超时回收。
如何监控线程池?
通过ThreadPoolExecutor
提供的方法:
getPoolSize()
:当前线程数。getActiveCount()
:活动线程数。getQueue().size()
:队列积压任务数。掌握线程池需深入理解其参数协同逻辑(核心/最大线程数、队列容量)、内置实现差异(如CachedThreadPool
的风险)、资源管理思想(复用 vs 销毁)。面试中需结合场景说明配置选择(如IO密集型任务配大队列+高线程数),并强调生产环境推荐手动创建线程池(避免Executors的潜在问题)。
文末寄语