线程池FAQ

news/2025/11/11 23:13:08/文章来源:https://www.cnblogs.com/irobotzz/p/19211884

线程池FAQ

线程池FAQ


0. 你将学到什么?

  • 线程池到底是什么、解决什么问题

  • 线程池怎么接任务→排队→扩容→执行→回收

  • SingleThreadExecutor 的作用与用法

  • 有界队列是啥,和 maximumPoolSize 有啥关系

  • 拒绝策略为什么存在、怎么选

  • 拒绝了怎么办(实操模板)

  • CPU 密集 vs I/O 密集,线程数到底设多少

  • 常见坑与“一键可用”代码模板


1. 线程池是什么?为啥不用“new Thread 走天下”?

一句话:线程池 = “可复用的工人队伍 + 等活的队列 + 排队/扩容/拒绝的规矩”。
解决三件事:

  1. 避免频繁创建/销毁线程的成本;

  2. 统一管理并发度,别把机器或下游打爆

  3. 有规矩(排队、背压、拒绝),系统高峰能优雅退让


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 的“稳妥口径”)

  1. 先判断类型
  • CPU 密集:core ≈ Ncpumax ≈ Ncpu~Ncpu+2,队列小一点。

  • I/O 密集:core ≈ Ncpumax ≈ Ncpu×(2~8),队列中等有界,配超时/限流

  1. 给队列一个上限cap ≈ 目标QPS × 允许排队秒数(保留 30% 余量)。

  2. 拒绝策略:同步强一致→CallerRuns/Abort;弱一致→自定义降级或丢弃(一定打点)。

  3. 监控 5 指标:CPU/上下文切换、队列长度、拒绝次数、等待/执行 P95/P99、下游服务负载。

  4. 压测—收敛

  • 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,一经查实,立即删除!

相关文章

Python Threading new thread

import threading import time import uuid from datetime import datetimedef print_time_uuid(num=1000):for a in range(1,num+1):print(f{a},{datetime.now()}_{uuid.uuid4().hex}\n)time.sleep(1)def print_uuid_…

从同步耦合到异步解耦:消息中间件如何重塑系统间的通信范式?

从同步耦合到异步解耦:消息中间件如何重塑系统间的通信范式?当成百上千的服务需要相互协作时,它们之间的通信模式变得至关重要。如果服务间采用紧密耦合的同步调用,一个服务的延迟或故障,就可能引发连锁反应,导致…

深入理解OpenWrt生态:LuCI、UCI、ubus与rpcd的协同工作机制 - 实践

深入理解OpenWrt生态:LuCI、UCI、ubus与rpcd的协同工作机制 - 实践2025-11-11 23:02 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !…

251111重点

251111重点在以前人们学习知识要逐字逐句,究根问底,才能在脑海里有一个框架的概念,归根结底,是缺乏好的老师,但是现在用心理学的话说就是搁置,不明白的地方有人知道(ai),可以先搁置,用自然语言理解,很容易就有…

第22天(简单题中等题 二分查找)

打卡第二十二天 1道简单题+3道中等题题目:思路:代码: class Solution { public:bool search(vector<int> &nums, int target) {int n = nums.size();if (n == 0) {//数组为空直接返回 falsereturn false;}if…

In the name of capitalists

So we have Harvard University, Stanford University. Whatever its Japan, Korea, or China, India, I never found University names that are more narcissistic than Americans. Indians are usually quiet just …

2025.11.11总结

今天在百度智能云上找api接口,因为大作业要求,需要做一个集文本生成,语音合成,ai作画三合一的人工智能的项目。 对于第一次使用模型来说,比较艰难,界面不熟悉,文档看不懂,没有现成可参考的视频,较新的手把手教…

K8S百万资源预list加载数据方案

K8S百万资源预list加载数据方案联邦控制器资源已经超过百万,每次重启时,需要一次性list所有资源,需要10分钟,给服务启动带来很多风险。 现通过主从预list加载数据,避免升级或者leader切换过程中长时间拉取数据。/…

102302105汪晓红数据采集作业2

第二次作业 作业①: 作业代码和图片: 核心代码:点击查看代码 # 主程序 url = "http://www.weather.com.cn/weather/101010100.shtml" city = "北京"# 初始化数据库 conn = setup_database()try:…

【数据结构】:链表的核心实现与运行解析

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

11.11每日总结

今天主要的课程有人机交互技术和软件构造。软考结束了 唉 已经做好下学期再努力试一次的准备了。今天还完善了心理健康平台的设计,继续加油

Meta AI 推出全语种语音识别系统,支持 1600+语言;谢赛宁、李飞飞、LeCun 联手发布「空间超感知」AI 框架丨日报

开发者朋友们大家好:这里是 「RTE 开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度…

Python Socket网络编程

1. Socket参数介绍 服务器端server = socket.socket(AF.INET,sock.SOCK_STREAM)Socket Typessocket.SOCK_STREAM #for tcpsocket.SOCK_DGRAM #for udp socket.SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、…

拥护向量机(SVM)(二)---优化算法

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

英语翻译题做法

🔹快速浏览全文和完形填空一样,做翻译题前,我先快速浏览一遍全文,大概知道文章讲什么、关于什么。如果时间充裕,可以这样做;但如果考试时间紧张,直接读划线句的翻译部分。重点看首尾两段,也能大致把握主旨。�…

Python show memory

py -m pip install psutil import os import psutil import asyncio import time from datetime import datetimeclass Book:def __init__(self,id,name,author,isbn,title,topic):self.id=idself.name=nameself.autho…

LeetCode - 1171. - 教程

LeetCode - 1171. - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

研发度量DORA+SPACE+OST 影响模型

目录总结DORA 指标Space指标传统指标参考资料 总结 作为研发总监,建议您建立一个三层指标仪表盘:顶层(DORA + 业务结果): 关注结果和对业务的贡献。这是您向 CEO 或董事会汇报的指标。核心 DORA 4 指标。 功能发布…

断句

文言文断句,传统上称为“句读”,明辨“句读”是阅读文言文最基本的方法;文言文断句,在通读全文、了解大意的基础上,可借助以下几种方法断句:一、借助虚词标志性词语断句 虚词是明辨句读的重要标志,尤其是代词、…

GBT - What is gradient-boosted tree regression?

GBT - What is gradient-boosted tree regression?Gradient-Boosted Tree Regression (GBT Regression) — also called Gradient Boosted Regression Trees (GBRT) or Gradient Boosting Regression — is a powerfu…