一位大厂面试官的灵魂发问:Executor 和 Executors 有什么区别?



你有没有被"线程池"打过脸?

先说个故事吧。

上个月我去面一家知名大厂,二面官看起来特别和蔼,就像楼下便利店大叔那种感觉。我本以为这一面轻轻松松,没想到......

面试官:你了解 Java 的线程池吗?

我:嗯嗯,知道的,用 Executors 创建线程池嘛,挺方便的,比如 Executors.newFixedThreadPool(10) 这种。

面试官点点头,露出诡异的微笑:那你知道为啥不推荐用 Executors 吗?

我:啊......?不是挺好用的吗?这......

空气突然安静。

我努力回忆当年看的 Java 并发编程艺术,结果脑袋一片空白,支支吾吾地说了几句含糊其辞的话,眼看着面试官的眉头越皱越紧。

面试官叹了口气,说:"没事,这个问题很多人都答不上来。"

当时我就一个念头:

线程池啊线程池,你这是给我上了一课!

于是,面试回来我连夜查文档、翻源码、画图、写博客,发誓下次再被问到这个问题,我一定把它讲得明明白白,像讲故事一样讲给别人听!

今天,就让我把这个故事讲完,也希望你不要像当初的我一样,被这道"Executors 和 ThreadPoolExecutor 的区别"给绊倒。

Executors 是糖,ThreadPoolExecutor 是本体

1. Executors 是啥?

Executors 是 Java 提供的一个工具类 ,里面提供了一堆静态方法,可以帮你方便快捷地创建各种线程池。

比如这些:

这些方法看起来是不是很优雅?的确,好看,好用,好记,用它可以一行代码创建线程池,谁不爱呢?

但,这也埋下了一个雷......

2. ThreadPoolExecutor 才是真正的线程池实现

ThreadPoolExecutor 是 java.util.concurrent 包下的核心类,它才是线程池的真正实现者。Executors 内部就是调用了它来构造不同类型的线程池。

我们来看一个手动创建线程池的例子:

这个构造方法虽然啰嗦,但每一个参数你都可以控制! 这就是和 Executors 最大的区别!

用 Executors 是"糖衣炮弹",吃起来爽,背后全是坑。

为什么说 Executors 不推荐用了?

现在你可能会问,Executors 不是封装好的吗?为啥还说它是"坑"?

原因就三个字:

不可控!

1. Executors.newFixedThreadPool()

它底层用的是:

重点来了:它用了一个无限长的阻塞队列LinkedBlockingQueue!

这意味着啥?

  • 如果你提交了成千上万个任务,线程池不扩容,任务全都堆在队列里,可能会导致内存暴涨、OOM(Out Of Memory)

简直是温水煮青蛙!

2. Executors.newCachedThreadPool()

它底层是这样的:

看出来了吗?

  • 核心线程数是 0
  • 最大线程数是 Integer.MAX_VALUE(20 多亿!)
  • 队列是 SynchronousQueue(不会缓存任务)

这意味着:

  • 你每提交一个任务,它就会尝试新建线程,直到撑爆你的 CPU 或内存!

所以,不加限制地用 CachedThreadPool,风险极大。

3. Executors.newSingleThreadExecutor()

同样的,底层也用了无限长的 LinkedBlockingQueue。

一旦处理不过来,任务又堆积如山。

4、总结一下

所以,阿里巴巴的《Java开发手册》中明确写到:

  • 线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样规避资源耗尽的风险。

正确姿势:手动创建线程池

那我们应该怎么做?

老老实实用 ThreadPoolExecutor,自己掌控线程数和队列容量

比如一个推荐的线程池创建方式:

这样,你能控制最大线程数量、队列容量、线程回收时间、拒绝策略,一切尽在掌握中。

面试官到底想听你说什么?

你以为面试官问你"Executors 和 ThreadPoolExecutor 有什么区别",是想听你背 API 吗?

No!他想听的是你是否理解背后的风险,是否有工程实践意识。

如果你能这样回答他:

"虽然 Executors 提供了便捷的方法,但由于它默认采用无限队列或无限线程,容易引发内存溢出或系统负载问题,因此我们推荐使用 ThreadPoolExecutor 并手动设置参数,避免系统崩溃。"

你说完这段,面试官多半会点头微笑,可能还会多给你一些面试分。

常见线程池参数详解(收藏版)

再来一个彩蛋:线程池调优建议

  • 对于高并发但执行时间短的任务,使用 FixedThreadPool 配有限长队列;
  • 对于执行时间长的任务,应控制线程数,避免占满 CPU;
  • 对于I/O密集型任务,可以设置核心线程略高于 CPU 核心数;
  • 别忘了设置合理的拒绝策略,比如 CallerRunsPolicy 能在任务过载时回退到调用者线程执行。

最后,小米的面试反杀记

就在上周,我又去面了一家大厂。

这次,面试官又问:

"你说说 Executors 和 ThreadPoolExecutor 的区别。"

我一笑,娓娓道来,从源码到风险,再到推荐方案,说得对方频频点头。

最终,HR 面说:

"你这回答比我们内部文档都清楚。"

我终于体会到:

被一道题打败,不是终点;弄懂它,讲出来,就是你进阶的开始。

END

我是小米,感谢你的阅读。

如果你喜欢这种"讲故事 + 技术干货"的文章风格,欢迎点个 ,或者分享给你身边也在准备面试的小伙伴~

下期我打算写:Future、CompletableFuture 和线程池的终极关系图解,你感兴趣吗?

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号"软件求生",获取更多技术干货!

相关推荐
写bug写bug2 分钟前
掌握 Spring 中的 WebClient
java·后端·spring
麓殇⊙8 分钟前
spring--整合Mybatis详解
java·spring·mybatis
长安明月12 分钟前
Java 实现 List<String> 与 String 互转
java·list
慕容静漪15 分钟前
本地部署Code Llama大模型结合Text generation Web UI远程运行LLM
开发语言·后端·golang
bobz96518 分钟前
AI-2-1
后端
zilong_zzz20 分钟前
系统编程3(共享内存/信号量)
java·开发语言
字节源流29 分钟前
【RabbitMQ】死信队列
java·rabbitmq·java-rabbitmq
五行星辰36 分钟前
SAX解析XML:Java程序员的“刑侦破案式“数据处理
xml·java·开发语言
向哆哆40 分钟前
Java 开发工具:从 Eclipse 到 IntelliJ IDEA 的进化之路
java·eclipse·intellij-idea
你是狒狒吗1 小时前
HttpServletRequest是什么
java