在线 Java 面试刷题已更新239题图文并茂https://www.quanxiaoha.com/java-interview面试考察点基础掌握度面试官不仅仅是想知道你会不会创建线程池更是想知道你是否清楚 Java 并发包中线程池的分类和适用场景能否根据业务特点选择合适的类型。生产实践意识考察你是否了解Executors工厂方法的潜在风险无界队列导致 OOM、无限线程导致系统崩溃以及为什么阿里开发手册明令禁止在生产环境使用。原理理解深度如果你只会调用 API 创建但不理解线程池的执行流程核心线程 → 队列 → 非核心线程 → 拒绝和 7 个核心参数的含义说明只是 “会用” 而非 “懂原理” 。核心答案Java 中创建线程池主要有4 种方式创建方式核心类适用场景推荐指数Executors工厂方法Executors快速原型、测试⚠️ 禁止生产使用手动构造ThreadPoolExecutor通用业务场景✅强烈推荐定时任务ScheduledThreadPoolExecutor延迟/周期执行✅ 推荐分治计算ForkJoinPool递归分解、并行计算✅ 特定场景一句话总结生产环境必须使用ThreadPoolExecutor手动构造避免Executors的隐患。深度解析一、线程池执行流程在介绍创建方式之前必须先理解线程池的执行流程否则参数配置就是 “盲人摸象” 。线程池执行任务流程图图示讲解上图展示了线程池执行任务的完整流程整体分为 4 个阶段步骤 1 - 判断核心线程当有新任务提交时首先判断当前线程数是否小于核心线程数corePoolSize。如果是则直接创建新的核心线程来执行任务不需要排队。这个阶段是 “有人就干活” 。步骤 2 - 加入队列如果当前线程数已经达到核心线程数新任务会尝试加入工作队列workQueue。队列起到了 “缓冲” 的作用让任务先排队等待。步骤 3 - 创建非核心线程如果队列也满了且当前线程数小于最大线程数maximumPoolSize则会创建非核心线程来执行任务。这是 “人手不够就招临时工” 的阶段。步骤 4 - 执行拒绝策略如果队列满了线程数也达到最大值就会执行拒绝策略。这是 “实在处理不了就拒绝” 的阶段。关键点线程池不是“先把线程创建满再排队” 而是按照核心线程 → 队列 → 非核心线程 → 拒绝的顺序处理任务。这个顺序很重要它决定了队列的容量会直接影响何时创建非核心线程。二、方式 1Executors 工厂方法⚠️ 生产环境禁止使用Executors类提供了 4 种快捷创建方式看起来很方便但都存在严重隐患// ❌ 固定大小线程池 ExecutorService fixedPool Executors.newFixedThreadPool(10); // ❌ 缓存线程池 ExecutorService cachedPool Executors.newCachedThreadPool(); // ❌ 单线程池 ExecutorService singlePool Executors.newSingleThreadExecutor(); // 定时任务线程池 ScheduledExecutorService scheduledPool Executors.newScheduledThreadPool(5);问题出在哪里Executors 为什么被禁止图示讲解上图展示了Executors两种主要工厂方法的内部实现问题newFixedThreadPool 和 newSingleThreadExecutor的问题在于使用了LinkedBlockingQueue这是一个无界队列容量为Integer.MAX_VALUE。当任务提交速度超过处理速度时队列会无限增长最终导致内存溢出OOM。newCachedThreadPool的问题在于最大线程数设置为Integer.MAX_VALUE相当于不限制线程数。配合容量为 0 的SynchronousQueue每个任务都会创建新线程。在高并发场景下可能瞬间创建数万个线程导致 CPU 飙升、系统崩溃。“阿里 Java 开发手册明确规定线程池不允许使用 Executors 去创建而是通过 ThreadPoolExecutor 的方式规避资源耗尽的风险。三、方式 2ThreadPoolExecutor 手动构造✅ 强烈推荐这是生产环境的正确姿势7 个参数完全由你掌控ThreadPoolExecutor executor new ThreadPoolExecutor( // ① corePoolSize核心线程数常驻线程即使空闲也不会被回收 5, // ② maximumPoolSize最大线程数 核心线程 非核心线程 10, // ③ keepAliveTime非核心线程空闲后的存活时间 60L, // ④ unit存活时间单位 TimeUnit.SECONDS, // ⑤ workQueue任务队列⚠️ 必须有界 new ArrayBlockingQueue(100), // ⑥ threadFactory线程工厂自定义线程名方便排查问题 r - { Thread t new Thread(r, “my-pool-“ new AtomicInteger(1).getAndIncrement()); t.setDaemon(false); // 用户线程防止 JVM 提前退出 return t; }, // ⑦ handler拒绝策略 new ThreadPoolExecutor.CallerRunsPolicy() );7 个核心参数详解参数含义配置建议corePoolSize核心线程数常驻不回收CPU 密集型N 1IO 密集型2N 或更高maximumPoolSize最大线程数核心 非核心不宜过大一般为核心线程的 1.5~2 倍keepAliveTime非核心线程空闲存活时间一般 60 秒足够太短会频繁创建销毁unit时间单位TimeUnit.SECONDSworkQueue任务队列⚠️必须有界推荐ArrayBlockingQueuethreadFactory线程工厂务必自定义线程名方便问题排查和监控handler拒绝策略队列满时触发根据业务敏感度选择“注N Runtime.getRuntime().availableProcessors()CPU 核数线程数配置的经验公式CPU 密集型加密、计算、图像处理线程数 CPU 核数 1IO 密集型网络请求、数据库查询、文件读写线程数 CPU 核数 × 2 或更高混合型根据 IO 等待时间占比调整公式线程数 N × (1 等待时间/计算时间)四、四种拒绝策略对比// 1️⃣ AbortPolicy默认—— 抛出 RejectedExecutionException // 适合关键业务宁可失败也不能静默丢弃 new ThreadPoolExecutor.AbortPolicy(); // 2️⃣ CallerRunsPolicy —— 由提交任务的线程自己执行 // 适合削峰填谷降低提交速度生产环境推荐 new ThreadPoolExecutor.CallerRunsPolicy(); // 3️⃣ DiscardPolicy —— 静默丢弃不抛异常 // 适合非核心业务日志采集等可丢弃场景 new ThreadPoolExecutor.DiscardPolicy(); // 4️⃣ DiscardOldestPolicy —— 丢弃队列中最老的任务再尝试提交 // 适合实时性要求高的场景老任务可以丢弃 new ThreadPoolExecutor.DiscardOldestPolicy();拒绝策略行为适用场景AbortPolicy抛异常快速失败关键业务需要感知失败CallerRunsPolicy调用者线程执行削峰填谷生产环境推荐DiscardPolicy静默丢弃非核心业务可容忍丢失DiscardOldestPolicy丢弃最老任务实时性要求高五、方式 3ScheduledThreadPoolExecutor定时任务专用适合需要延迟执行或周期性执行的场景// 创建定时任务线程池 ScheduledExecutorService scheduler new ScheduledThreadPoolExecutor(2); // ① 延迟执行3 秒后执行一次 scheduler.schedule(() - { System.out.println(“3 秒后执行一次“); }, 3, TimeUnit.SECONDS); // ② 固定频率执行不管上次是否完成 scheduler.scheduleAtFixedRate(() - { System.out.println(“每 5 秒执行一次“); }, 1, 5, TimeUnit.SECONDS); // ③ 固定延迟执行上次执行完后再等待 scheduler.scheduleWithFixedDelay(() - { System.out.println(“执行完后等 5 秒再执行“); }, 1, 5, TimeUnit.SECONDS);六、方式 4ForkJoinPool分治计算专用JDK 7 引入专门用于递归分解的计算密集型任务采用工作窃取算法// 示例大数组求和 ForkJoinPool pool new ForkJoinPool(4); long result pool.invoke(new SumTask(array, 0, array.length));适用场景大数组求和、并行排序、树的遍历、矩阵运算等可以递归分解的计算密集型任务。注意JDK 8 的parallelStream()底层默认使用ForkJoinPool.commonPool()。面试高频追问线程池的核心线程数和最大线程数如何配置CPU 密集型任务配置 N 1N 为 CPU 核数IO 密集型任务配置 2N 或更高。实际需要结合压测调整。线程池的队列满了怎么办会触发拒绝策略。生产环境推荐CallerRunsPolicy既能削峰又不会静默丢弃任务。如何优雅关闭线程池使用shutdown()停止接收新任务 awaitTermination()等待任务完成。如果超时还没完成再调用shutdownNow()。核心线程会被回收吗默认不会。但可以通过allowCoreThreadTimeOut(true)设置允许回收。常见面试变体“为什么阿里禁止使用 Executors 创建线程池”“ThreadPoolExecutor 的 7 个参数分别是什么意思”“线程池的拒绝策略有哪些如何选择”“如何合理配置线程池参数”“线程池的 execute() 和 submit() 有什么区别”记忆口诀执行顺序核心 → 队列 → 非核心 → 拒绝通俗理解先用正式员工核心线程忙不过来就排队队列队列满了招临时工非核心线程实在不行就拒绝拒绝策略。参数记忆5 个基本参数 2 个扩展参数 7 个参数基本核心数、最大数、存活时间、时间单位、队列扩展线程工厂、拒绝策略总结生产环境必须使用ThreadPoolExecutor手动构造避免Executors的无界队列和无限线程风险。核心是理解 “核心线程 → 队列 → 非核心线程 → 拒绝” 的执行流程根据 CPU 密集型N1或 IO 密集型2N合理配置线程数选择有界队列和合适的拒绝策略。加入小哈的星球你将获得:专属的项目实战4个项目 / 1v1 提问 / 简历修改 /Java 学习路线 /社群讨论 /学习打卡 / 每月赠书《仿小红书微服务架构》 已完结基于 Spring Cloud Alibaba Spring Boot 3.x JDK 17..., 点击查看项目介绍演示地址http://116.62.199.48:7070/《Spring AI 应用RAG 智能客服》已完结, 基于 Spring AI Spring Boot 3.x JDK 21《秒杀系统设计》正在更新中单体到微服务高并发架构演进《前后端分离博客项目全栈开发》已完结,演示链接http://116.62.199.48/项目阅读地址https://quanxiaoha.com/column截止目前累计输出 120w 字讲解图 4013 张还在持续爆肝中..戳我加入学习解锁全部项目已有4500小伙伴加入1. 我的私密学习小圈子从0到1手撸企业实战项目~ 2. 面试官Feign 第一次调用为什么会很慢大部分人答不上来 3. 面试官为什么 MyBatis 的 Mapper 接口不需要写实现类 4. 拼多多二面为什么有了线程还需要协程我额协程是啥...最近面试BAT整理一份面试资料《Java面试BATJ通关手册》覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。 获取方式点“在看”关注公众号并回复 Java 领取更多内容陆续奉上。PS因公众号平台更改了推送规则如果不想错过内容记得读完点一下“在看”加个“星标”这样每次新文章推送才会第一时间出现在你的订阅列表里。 点“在看”支持小哈呀谢谢啦