Java 线程池常见面试坑点总结
                           
天天向上
发布: 2025-04-26 18:34:30

原创
279 人浏览过

本章节整理一份超实用的《线程池面试坑点》,方便快速记忆,如果在现场讲出来就会显得又专业又高效!


1. 为什么不推荐直接使用 Executors 创建线程池?

答:

因为 Executors 工具类(如 newFixedThreadPoolnewCachedThreadPool)默认使用的队列是无界的,比如 LinkedBlockingQueue,这样在高并发情况下容易导致内存耗尽(OOM),从而引发系统崩溃。

正确做法是手动使用 ThreadPoolExecutor,并且合理设置核心参数(核心线程数、最大线程数、队列容量、拒绝策略等)。

一句话记忆版:
✅ “Executors 隐患大,ThreadPoolExecutor 可控、安全。”


2. 如何自定义 ThreadPoolExecutor

答:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,    // 核心线程数
    maximumPoolSize, // 最大线程数
    keepAliveTime,   // 空闲线程最大存活时间
    TimeUnit.SECONDS,// 时间单位
    workQueue,       // 阻塞队列
    threadFactory,   // 线程工厂
    handler          // 拒绝策略
);

一般推荐:

  • 阻塞队列用 ArrayBlockingQueue(有界)
  • 拒绝策略根据业务选定(比如默认抛异常、CallerRunsPolicy)

3. 常见的线程池拒绝策略有哪些?应用场景是什么?

答:

策略说明适用场景示例
AbortPolicy(默认)直接抛异常,任务被拒绝对实时性要求非常高的系统
CallerRunsPolicy提交任务线程自己执行可以降级处理,保护线程池
DiscardPolicy直接丢弃新提交的任务可容忍少量任务丢失的场景
DiscardOldestPolicy丢弃最老的排队任务,执行新任务保证新请求优先场景

一句话记忆版:
✅ “Abort 抛异常,Caller 自己干,Discard 扔掉任务,DiscardOldest 扔最老的。”


4. 如何配置线程池的核心参数?(再强化一遍)

答:

  • CPU 密集型 ➔ 核心线程数 = CPU 核数 + 1
  • IO 密集型 ➔ 核心线程数 = 2 * CPU 核数(或更多)
  • 队列大小 ➔ 根据业务量评估(有界队列!)
  • 最大线程数 ➔ 一般是核心线程数的 1.5~2 倍
  • 拒绝策略 ➔ 业务特点决定(实时性高就抛异常,可降级就 CallerRuns)

5. 线程池什么时候适合用固定线程池 (FixedThreadPool)?

答:

  • 任务数量可控且执行时间较长。
  • 系统负载比较稳定。
  • 比如后台邮件发送、日志处理等固定任务。

一句话记忆版:
✅ “任务稳定、执行慢,FixedThreadPool 刚刚好。”


6. 什么场景适合用缓存线程池 (CachedThreadPool)?

答:

  • 短期大量并发任务、执行时间短。
  • 如处理大量短小的异步请求。

风险提醒: CachedThreadPool 无界线程数 ➔ 容易 OOM,要小心用!


7. 线程池的核心线程数可以回收吗?

答:

  • 默认核心线程不会回收。
  • 如果调用 allowCoreThreadTimeOut(true),即使是核心线程,空闲时间超过 keepAliveTime 也会被回收。

最后附送一句万能收尾回答(面试压轴)

当面试官问到线程池相关任何问题最后结尾时,可以用下面这句总结,超级加分:

“在高并发系统中,线程池是资源隔离和负载保护的重要手段,合理配置线程池参数,结合限流、熔断、降级等机制,可以有效保障系统稳定性和高可用性。”


更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *