文章目录
Java中的Executor框架及其优点:
1、简化线程管理: Executor框架通过提供线程池管理机制,简化了线程的创建和分配。
2、资源优化: 通过线程复用,减少了线程创建和销毁的性能开销。
3、提供调度和控制: Executor框架提供了灵活的线程调度和执行控制机制。

📢 王二被骂哭!new Thread () 炸服后,哇哥掏出 Executor 救场|Java 并发篇 1

零、引入
“服务器直接 OOM,订单全卡了!” 技术部传来王二的哀嚎,他刚写的 “商品库存同步” 代码上线 5 分钟就炸了,老板拿着保温杯站在他身后,脸色比 IDE 的深色模式还黑。王二屏幕上满是OutOfMemoryError,代码里清一色的new Thread()——1000 个库存同步任务,他就建了 1000 个线程。
“你这是把服务器当菜市场了?” 哇哥叼着奶茶走过来,手指戳着屏幕,“线程是重量级资源,创建销毁比你买杯奶茶还费钱,1000 个线程同时跑,内存不炸才怪。” 说着敲了三行代码,替换掉王二的new Thread(),服务器立马恢复正常。
这篇就跟着哇哥和王二,搞懂 Executor 框架到底是啥 —— 它不是 “新语法”,而是 Java 给你备好的 “线程管家”,看完你再也不用写new Thread()这种 “炸服代码”。点赞 + 关注,下次面试被问并发,你比王二稳 10 倍!

一、王二的 “炸服代码”:new Thread () 的三大死罪
王二的库存同步代码很简单:1000 个商品,每个商品开一个线程同步库存到数据库。本地跑着挺溜,一到线上就歇菜。哇哥把他的代码贴在白板上,圈出三个致命坑。
❌王二的 “自杀式” 代码
import java.util.concurrent.CountDownLatch;
public class ThreadOomDemo {
// 1000个库存同步任务
static final int TASK_NUM = 1000;
static CountDownLatch latch = new CountDownLatch(TASK_NUM);
public static void main(String[] args) {
for (int i = 0; i < TASK_NUM; i++) {
int goodsId = i; // 商品ID
// 每个任务开一个新线程(致命操作)
new Thread(() -> {
try {
// 模拟库存同步:查数据库→改库存→写日志
System.out.println("同步商品" + goodsId + "库存");
Thread.sleep(100); // 模拟数据库耗时
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}).start();
}
try {
latch.await();
System.out.println("所有库存同步完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
✔️** 哇哥怒怼三大死罪**
- 资源耗尽罪:线程是 “重量级选手”,创建时要占 1-2MB 栈内存,1000 个线程就是 1-2GB,服务器内存直接被吃光,OOM 没商量;
- 效率低下罪:线程创建、销毁要切换 CPU 上下文,比你下楼买包烟还费时间,1000 个线程频繁启停,CPU 全在 “打杂”,正事一点没干;
- 管理混乱罪:线程散养,没统一管控 —— 哪个线程抛异常了?任务执行到哪了?全是糊涂账,出问题查日志查到天亮。
“你这代码就像在马路上随便拉人干活,” 哇哥喝了口奶茶,“来人就招,人多了住不下就炸;活干完了人就走,下次再招人又得重新培训 ——Executor 框架就是给你配个‘人力资源部’,线程统一招、统一管、重复用,省钱又省心。”
二、Executor 框架:Java 给你备好的 “线程管家”
哇哥擦了擦白板,画了个简单的架构图:“Executor 框架不是一个类,是一套‘线程管理体系’,核心就三个东西:顶层接口、线程池实现、工具类。你不用自己建线程,只需要把任务交给他,剩下的全不用管。”
Executor 框架核心 “三件套”(人话版)

“简单说,你把任务(Runnable/Callable)交给 ExecutorService,它会用池子里的线程执行,线程用完不销毁,留着下次再用 —— 这就是‘线程池’的核心思想,复用线程,减少开销。”
📲 王二的第一次优化:用 FixedThreadPool 替换 new Thread ()

哇哥先教王二用最常用的FixedThreadPool(固定数量线程池),核心是 “线程数固定,任务排队执行”,适合王二这种 “任务数量多但线程不能乱开” 的场景。
优化后的代码(再也不 OOM)
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorFixedDemo {
static final int TASK_NUM = 1000;
static CountDownLatch latch = new CountDownLatch(TASK_NUM);
public static void main(String[] args) {
// 1. 用Executors创建固定线程池:核心线程数=10(根据CPU核心数调整)
ExecutorService threadPool = Executors.newFixedThreadPool(10);
for (int i = 0; i < TASK_NUM; i++) {
int goodsId = i;
// 2. 提交任务给线程池,不用自己new Thread()
threadPool.submit(() -> {
try {
System.out.println("同步商品" + goodsId + "库存,执行线程:" + Thread.currentThread().getName());
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
});
}
try {
latch.await();
System.out.println("所有库存同步完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 3. 关闭线程池:先拒绝新任务,等现有任务跑完再关闭
threadPool.shutdown();
}
}
}
运行效果:线程重复用,内存稳如狗
王二跑起来发现,控制台里线程名全是pool-1-thread-1到pool-1-thread-10,1000 个任务靠 10 个线程就搞定了,内存占用连之前的 1/10 都不到。
程池里的线程是‘复用’的,” 哇哥指着日志,“第一个任务用完线程 1,线程 1 不会死,接着执行第二个任务,这样 10 个线程就能扛 1000 个任务,内存能炸才怪。”
三、Executors 的 “三大常用线程池”:按需挑,不用瞎造
哇哥说,Executors 给你备了 “三款现成的线程池”,就像外卖平台的 “套餐”,不用你自己买菜做饭,按需选就行。他给王二列了个 “点餐指南”。
1. FixedThreadPool(固定线程数)
- 特点:线程数固定,任务多了就放队列里排队;
- 核心参数:只需要传 “核心线程数”(比如 10);
- 场景:任务量大但并发不能太高(比如库存同步、订单处理);
- 代码:Executors.newFixedThreadPool(10)。
2. CachedThreadPool(缓存型线程池)
- 特点:线程数 “按需增减”,没任务时线程会在 60 秒后销毁;
- 优势:响应快,适合短期、突发的小任务;
- 坑:任务太多时可能创建大量线程,有 OOM 风险;
- 代码:Executors.newCachedThreadPool()。
📢 王二的小试牛刀:用 CachedThreadPool 处理临时任务
比如处理一批 “用户登录日志”,任务小且执行快,用 CachedThreadPool 最合适:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorCachedDemo {
public static void main(String[] args) {
// 缓存型线程池:线程数随任务增减
ExecutorService cachedPool = Executors.newCachedThreadPool();
for (int i = 0; i < 20; i++) {
int userId = i;
cachedPool.submit(() -> {
System.out.println("记录用户" + userId + "登录日志,线程:" + Thread.currentThread().getName());
});
}
cachedPool.shutdown();
}
}
3. SingleThreadExecutor(单线程线程池)
- 特点:只有 1 个线程,任务按顺序执行;
- 场景:需要 “串行执行” 的任务(比如数据库备份、日志归档);
- 优势:不用自己加锁,天然线程安全;
- 代码:Executors.newSingleThreadExecutor()。
❓哇哥的灵魂提问:为啥不用 new Thread () 做串行?
“比如你要按顺序备份 10 个数据库,用 SingleThreadExecutor 不用加锁,任务排队执行;用 new Thread () 的话,你得自己写代码控制顺序,麻烦还容易错。”
四、总结:Executor 框架的核心优势(王二记满 3 页笔记)
王二掏出小本本,把哇哥的话记成 “傻瓜式总结”:
- 省钱:复用线程,减少创建销毁的开销,CPU 不用再 “打杂”;
- 安全:控制线程数量,避免 OOM,服务器稳如老狗;
- 省心:统一管理线程,任务提交、线程关闭全有规范,出问题好排查;
- 灵活:现成线程池按需挑,不用自己造轮子。
彩蛋:哇哥的 “黑历史”
“我刚工作时,比你还虎,” 哇哥笑着说,“用 new Thread () 跑 2000 个任务,直接把测试环境搞挂了,领导让我把《Java 并发编程实战》抄了一遍 —— 现在我写并发代码,先想‘Executor 有没有现成的池’。”
下一篇预告:
王二用 FixedThreadPool 跑了两天,又遇到新问题:“任务堆积在队列里,用户投诉库存同步太慢!” 哇哥说这是 “线程池参数没配对”—— 下一篇我们扒透:
- 线程池的核心参数(核心线程数、最大线程数、队列、拒绝策略);
- 怎么自定义线程池,而不是只靠 Executors;
- 定时任务线程池(ScheduledExecutorService)怎么用;
170万+

被折叠的 条评论
为什么被折叠?



