线程池FAQ
线程池FAQ
0. 你将学到什么?
-
线程池到底是什么、解决什么问题
-
线程池怎么接任务→排队→扩容→执行→回收
-
SingleThreadExecutor 的作用与用法
-
有界队列是啥,和 maximumPoolSize 有啥关系
-
拒绝策略为什么存在、怎么选
-
被拒绝了怎么办(实操模板)
-
CPU 密集 vs I/O 密集,线程数到底设多少
-
常见坑与“一键可用”代码模板
1. 线程池是什么?为啥不用“new Thread 走天下”?
一句话:线程池 = “可复用的工人队伍 + 等活的队列 + 排队/扩容/拒绝的规矩”。
解决三件事:
-
避免频繁创建/销毁线程的成本;
-
统一管理并发度,别把机器或下游打爆;
-
有规矩(排队、背压、拒绝),系统高峰能优雅退让。
2. 线程池怎么工作?(最关键的一张图)
┌──── submit(task) ────┐▼ │
运行线程 < corePoolSize ? 是 → 直接新建“核心线程”执行(不入队)│ │ 否▼ │尝试入队 workQueue —— 成功 → 排队等待│ │ 失败(队列满了)▼ │运行线程 < maximumPoolSize ? 是 → 新建“非核心线程”执行这个新任务│ │ 否└────────────→ 触发“拒绝策略”
细节点名:当队列满了时,新建的“非核心线程”先执行“本次提交的任务”,不是先去搬队列里的旧任务;等它跑完再到队列里拿下一份。这意味着全局顺序不保证(队列内部仍保持 FIFO)。
3. 什么是 SingleThreadExecutor?有什么用?
-
定义:始终只有1 个工作线程,任务按提交顺序一个接一个跑;线程挂了会自动补一个。
-
用途:
-
顺序写日志/文件;
-
单连接 I/O(串口/套接字);
-
需要“同一时刻只允许一个任务执行”的场景;
-
“按 Key 串行,整体并行”可用多组 SingleThreadExecutor 做“分片串行”。
-
-
创建(工程化版):
ThreadPoolExecutor one = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1000), // 有界:别让队列无限长r -> new Thread(r, "single-worker"),new ThreadPoolExecutor.CallerRunsPolicy() // 背压:队满时调用方自己跑
);
4. 有界队列是啥?为什么“强烈建议用有界队列”?
有界队列 = 有上限的队列(如 ArrayBlockingQueue(1000))。
意义:
-
形成背压(满了就慢/拒),保护内存和尾延;
-
配合拒绝策略,高峰期可控退让,不至于无声堆积。
API 行为小抄: -
put会阻塞直到有空位; -
offer立即失败(返回 false); -
offer(timeout)限时等待。
5. maximumPoolSize 和队列到底啥关系?
-
接纳顺序是核心→队列→非核心(到 max)→拒绝。
-
有界队列:队列不满就不扩容;队列满了才创建非核心线程,直到
maximumPoolSize。 -
无界队列:几乎永远不满,
maximumPoolSize基本形同虚设。 -
SynchronousQueue(0 容量):不排队,来一个就尽快扩线程,最容易跑到
max(要防线程风暴)。
直观理解:队列像闸门。闸门开得大(队列大),晚扩容;闸门小,早扩容。
6. 线程会并发到多少?和 CPU 核心是什么关系?
-
最多同时并行执行的线程数 ≤ maximumPoolSize(和队列策略有关)。
-
跟 CPU 逻辑核有关,但不等于:
-
CPU 密集:
max ≈ CPU核数(±1~2),再多只会增加上下文切换; -
I/O 密集:
max可 大于 CPU 核数(甚至数倍),因为很多线程在等待 I/O不占 CPU,但要配超时/限流,别把下游打爆。
-
-
粗估公式:需要线程数 ≈ Ncpu × (1 + 等待时间/计算时间)。
7. 为什么会“拒绝任务”?拒绝策略有哪些?
为什么:当核心满 + 队列满 + 已达 maximumPoolSize,系统已过载。再接单只会:内存涨、尾延飙、下游崩。
四种内置策略:
-
AbortPolicy(默认):抛异常,最“吵”,最好监控;
-
CallerRunsPolicy:把任务退给调用线程自己跑,形成自然背压;
-
DiscardPolicy:静默丢弃(风险大,谨慎用);
-
DiscardOldestPolicy:丢队首最旧的再尝试入队(会破坏全局顺序)。
选策略的关键:你的业务能不能丢?能不能等?要不要把“忙”反馈给调用方?(详见第 9 节)
8. 被拒绝了怎么办?(三类场景,给你模板就能用)
8.1 强一致/不可丢(如下单、转账)
- 有限次重试 + 指数回退 + 幂等;仍失败→显式报忙(429/503)
static final int MAX_RETRY = 2;
T submitCritical(Callable<T> task, ThreadPoolExecutor pool) {int a=0; long back=20;for(;;){try { return pool.submit(task).get(800, TimeUnit.MILLISECONDS); }catch(RejectedExecutionException e){if(a++>=MAX_RETRY) throw new ServiceUnavailableException("busy");Thread.sleep(back + ThreadLocalRandom.current().nextLong(back/2+1));back = Math.min(back*2, 500);}}
}
8.2 同步接口,可降速(页面/网关)
- 用 CallerRunsPolicy:队满时让调用线程自己跑,RT 变长=用户可感知的背压。
8.3 弱一致/可丢(埋点/异步日志)
- 本地有界缓冲 + 批量 + 打点告警;缓冲满→丢弃或落盘。
9. 小白怎么配参数?(从 0 到 1 的“稳妥口径”)
- 先判断类型
-
CPU 密集:
core ≈ Ncpu,max ≈ Ncpu~Ncpu+2,队列小一点。 -
I/O 密集:
core ≈ Ncpu,max ≈ Ncpu×(2~8),队列中等有界,配超时/限流。
-
给队列一个上限:
cap ≈ 目标QPS × 允许排队秒数(保留 30% 余量)。 -
拒绝策略:同步强一致→
CallerRuns/Abort;弱一致→自定义降级或丢弃(一定打点)。 -
监控 5 指标:CPU/上下文切换、队列长度、拒绝次数、等待/执行 P95/P99、下游服务负载。
-
压测—收敛:
-
P99 高→增
max或缩短任务时间/限流; -
CPU/切换高→降
max; -
下游报警多→先限流,不是盲目加线程。
生产模板(通用 I/O 偏多):
int ncpu = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor pool = new ThreadPoolExecutor(ncpu, ncpu * 4,60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2000), // 有界r -> { Thread t = new Thread(r, "biz-pool"); return t; },new ThreadPoolExecutor.CallerRunsPolicy() // 背压
);
// 可选:平滑峰谷
// pool.allowCoreThreadTimeOut(true);
10. 常见坑(踩一次就会记住)
-
无界队列 + 小 max:看似稳,实则高峰排队无限长,尾延/内存失控。
-
在池线程里阻塞等同池任务(
Future#get()/join()):线程饥饿/死锁。 -
把 I/O 阻塞任务和 CPU 计算搅在一个池:互相拖垮,建议分池。
-
ThreadLocal不清理:线程复用导致“脏数据粘连”。 -
静默丢弃:用
Discard却没打点=“无声事故”。
11. FAQ:两句到位的正确认知
-
Q:core=4,就只能同时 4 个线程执行吗?
A:不对。当队列满了,会新建“非核心线程”,最多到 maximumPoolSize 个并发线程。 -
Q:当队列满后新建线程会先清队吗?
A:不会。它先执行“当前提交的任务”,然后再从队列取后续。 -
Q:20 个 I/O 任务在 10 核 CPU 上是不是 10 个在等?
A:看情况。很多线程可能在 I/O 阻塞(不占 CPU),CPU 甚至跑不满;如果计算占比高,就会排队争时间片。
12. 一页“上线前检查清单”
-
用
new ThreadPoolExecutor(...),不要生产用Executors.*快捷池 -
有界队列,容量基于 QPS×可接受排队时长
-
core/max/queue与负载类型匹配(CPU vs I/O) -
拒绝策略明确且打点告警
-
关键路径超时、重试上限、幂等
-
指标齐全:活跃数、队列长、拒绝数、等待/执行 P95/P99、下游压力
-
压测包含“队满/拒绝”场景
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/962818.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!