当前位置: 首页 > ds >正文

【JUC】——线程池

目录

 

线程池

1.池状态

2.构造方法

3.拒绝策略

4.线程池类型

1.newFixedThreadPool(固定大小的线程池)

 2.newCacheThreadPool(带缓冲池的)

3.newSingleThreadExecutor(单线程线程池)

 5.提交任务方法

 1.submit

2.invokeall

​编辑

 3.invokeAny

6.关闭线程池

7.异步模式之工作线程

1.定义

 2.饥饿现象

8.线程池的7大核心参数

1.核心线程数

cpu密集型(视频处理)

IO密集型

线程池配置建议:

2.阻塞队列

✅ 含义:

✅ 为什么设 5000?

⚠️ 注意:

阻塞队列的选择:

3.最大线程数

为什么要设 200?

4.线程工厂

5.最佳参数配置实践

9.任务调度线程池

1.Timer的缺点

 2.任务调度线程池 newScheduledThreadPool

1.可以同时运行

2.出现异常也不影响

处理异常

3.定时执行

10.tomcat中哪里用到了线程池


 

线程池

1.池状态

2.构造方法

 核心线程和救急线程

核心线程都在执行任务,阻塞队列也满了,就会启用救急线程,执行完任务(救急线程有一个生存时间)就没了。

3.拒绝策略

 

4.线程池类型

1.newFixedThreadPool(固定大小的线程池)

 2.newCacheThreadPool(带缓冲池的)

3.newSingleThreadExecutor(单线程线程池)

 5.提交任务方法

 1.submit

 

2.invokeall

 3.invokeAny

哪个任务先执行完,就返回那个任务的结果,其他任务取消

 

6.关闭线程池

7.异步模式之工作线程

1.定义

 2.饥饿现象

线程数不足导致饥饿,一个又需要等另一个的结果才能执行。

用两个不同类型的线程池来解决即可

8.线程池的7大核心参数

1.核心线程数

cpu密集型(视频处理)

​CPU 密集型任务是指:任务主要消耗的是 CPU 资源,大部分时间都在做大量的计算、逻辑处理、加密解密、图像处理、算法运算等。这类任务的特点是:CPU 使用率高,但通常 I/O(磁盘、网络、数据库)操作很少或几乎没有。​

线程池配置建议:线程数不宜过多!​

因为 CPU 的核心数是有限的,线程多了只会造成:频繁上下文切换,cpu资源竞争激烈

一般推荐​CPU 核心数 + 1(或者 CPU 核心数 ~ 2 倍)​

IO密集型

​​IO 密集型任务是指:任务并不怎么消耗 CPU,而是在等待 I/O 操作完成,比如:

  • 调用 ​​HTTP 接口、OpenAPI、第三方服务​​
  • 访问 ​​数据库(MySQL、Redis、MongoDB)​​
  • 操作 ​​文件读写(上传下载、日志记录)​​
  • 调用 ​​消息队列(如 Kafka、RabbitMQ、RocketMQ)​​
  • ​​异步获取数据、远程服务调用、发消息等​
线程池配置建议:

​​可以设置更多的线程,因为线程经常在等待 I/O,而不是占用 CPU​​

线程数可以设为 ​​CPU 核心数的 2 倍、甚至 5~10 倍​​(视 I/O 等待时间长短而定)

 一般推荐的线程数:​​

​​CPU 核心数 × 2 ~ CPU 核心数 × 5,甚至到 10(视场景而定)​

2.阻塞队列

✅ 含义:
  • 当 ​​核心线程都在忙​​,新来的任务不会立即创建新线程,而是先进入队列等待
  • 这个参数就是 ​​阻塞队列的最大长度​
  • 如果队列也满了,才会去创建新线程(直到 maxPoolSize),再满了就触发拒绝策略
✅ 为什么设 5000?

是一个 ​​较大的队列,适合容纳突发的大量任务​

比如:你有一个 ​​定时任务扫描出 1万条超时订单,要异步处理​​,这个队列可以暂时存一部分,避免立即触发线程扩容或拒绝

⚠️ 注意:
  • ​队列越大,意味着任务可以积压得越多,但也意味着:​
  • 任务响应延迟可能变高(排在队列后面的任务要等很久)​
  • ​如果任务处理慢,队列积压过多可能导致 OOM 或系统雪崩​
  • ​队列太小,可能导致线程很快就满了,触发拒绝策略或扩容​

🔧 ​​建议:​

一般为 ​​100 ~ 10000​​,根据你的任务特性来权衡:

实时性要求高​​ → 队列别太大,避免延迟

​允许堆积、任务可延迟处理​​ → 可设大一点,比如 5000 ~ 10000•要配合 ​​监控队列积压情况​​,避免失控

阻塞队列的选择:

3.最大线程数

当 ​​核心线程都在忙,且任务队列也满了​​,线程池会继续创建新线程,直到达到最大线程数

超过这个数量后,新任务将触发 ​​拒绝策略​

为什么要设 200?

这是一个 ​​较大的上限值​​,适用于 ​​突发流量、任务队列也满了的情况下,线程池还能扩容应对​

比如:平时用 20 个核心线程处理日常请求,但 ​​大促 / 秒杀 / 拼团超时批量处理时,可能有大量任务瞬间涌入​​,线程池可以临时扩容到 200 来扛住

⚠️ 注意:

​200 是一个较高的上限,不是所有业务都适用​

如果你的任务是 ​​阻塞型、慢任务、或资源敏感型(比如调用外部接口、DB)​​,线程数太多反而会导致:

  • 线程上下文切换开销增大
  • 系统资源(CPU / 内存 / 文件句柄 / DB 连接)可能被拖垮
  • 所以 ​​maxPoolSize 一定要结合业务特点、服务器资源、队列大小谨慎设置!​

🔧 ​​建议:​

一般可设置为 corePoolSize 的 ​​3~10 倍​​,但要考虑:

4.线程工厂

  • 线程池中的线程 ​​不是凭空出现的​
  • 当任务来了,线程池会按规则使用已有线程;
  • 如果线程不够用了(达到了核心线程数、队列也满了、还没达到最大线程数),线程池就需要 ​​创建新的线程​
  • ​而这个新线程的创建过程,就是由 ThreadFactory 来完成的!​

✅ 它的核心方法只有一个:

public interface ThreadFactory {Thread newThread(Runnable r);
}

你给它一个任务(Runnable),它负责:

​​创建一个 Thread 对象​​​​,把这个 Runnable 任务绑定到这个 Thread 上​​​​返回这个 Thread,线程池随后会启动它去执行任务​

举例:

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;public class NamedThreadFactory implements ThreadFactory {private final String namePrefix;  // 线程名前缀,比如 "order-worker"private final AtomicInteger threadNumber = new AtomicInteger(1); // 线程编号public NamedThreadFactory(String namePrefix) {this.namePrefix = namePrefix;}@Overridepublic Thread newThread(Runnable r) {// 构造线程名:order-worker-1, order-worker-2, ...Thread t = new Thread(r, namePrefix + "-" + threadNumber.getAndIncrement());// 可选:设置为非守护线程(默认就是 false,即非守护线程)t.setDaemon(false);// 可选:设置线程优先级(默认是 Thread.NORM_PRIORITY = 5)t.setPriority(Thread.NORM_PRIORITY);// 可选:设置未捕获异常处理器t.setUncaughtExceptionHandler((thread, throwable) -> {System.err.println("线程 " + thread.getName() + " 发生异常: " + throwable.getMessage());});return t;}
}

通过 ​​线程工厂​​ 来定制线程行为,特别是:

  • 线程命名(用于日志和监控)
  • 线程分组
  • 异常处理
  • 线程上下文传递(如 MDC、TraceID

5.最佳参数配置实践

1.线程池参数一定要可配置化(你已经用 @ConfigurationProperties 做到了,很棒!)

  • ·不同环境(dev/test/prod)可以配不同的线程数
  • 根据压测结果动态调整

2.务必设置合理的队列大小 & 拒绝策略,并做好监控

  • ·比如队列积压超过 80%就报警
  • ·拒绝任务时要记录日志,可加入重试队列或死信队列

3.区分任务类型,不同业务使用不同线程池

  • 不要将所有异步任务都塞进一个线程池(比如支付、通知、日志不要混在一起!)
  • 推荐按业务隔离线程池,避免互相影响

4.线程池一定要加监控!

  • ·比如:活跃线程数、队列大小、拒绝次数、完成任务数可使用 Micrometer、Prometheus、Grafana等工具

5.推荐使用 Spring 的 ThreadPoolTaskExecutor或Alibaba的线程池工具类(如 Hippo4j、dynamic-tp)

  • 它们对线程池做了更好的封装、动态调整、监控支持

9.任务调度线程池

1.Timer的缺点

 2.任务调度线程池 newScheduledThreadPool

1.可以同时运行

只要核心线程数量够的话

上图可以发现,线程1执行较久并没有影响到线程2的执行

2.出现异常也不影响

处理异常

1.自己处理

try catch住

2.配合Future

3.定时执行

 但如果任务的执行时间大于间隔时间,就以任务的执行时间为准了,反正就是哪个大以哪个为准,避免任务的重叠。同时也引出了下面一个方法,是真正的任务和任务之间的间隔。

10.tomcat中哪里用到了线程池

http://www.xdnf.cn/news/19063.html

相关文章:

  • 点评项目(Redis中间件)第一部分Redis基础
  • docker run 后报错/bin/bash: /bin/bash: cannot execute binary file总结
  • 边缘计算:一场由物理定律发起的“计算革命”
  • 预测模型及超参数:2.传统机器学习:PLS及其改进
  • HarmonyOS 高效数据存储全攻略:从本地优化到分布式实战
  • 从 GRIT 到 WebUI:Chromium 内置资源加载与前端展示的完整链路解析
  • AI Agent 发展趋势与架构演进
  • 稳敏双态融合架构--架构师的练就
  • 【MES】工业4.0智能制造数字化工厂(数字车间、MES、ERP)解决方案:智能工厂体系架构、系统集成以及智能设计、生产、管理、仓储物流等
  • uvloop深度实践:从原理到高性能异步应用实战
  • http请求能支持多大内容的请求
  • 通义万相音频驱动视频模型Wan2.2-S2V重磅开源
  • 安卓接入通义千问AI的实现记录
  • 欧盟《人工智能法案》生效一年主要实施进展概览(二)
  • React 组件命名规范:为什么必须大写首字母蛊傲
  • 【Datawhale之Happy-LLM】Encoder-only模型篇 task05精华~
  • 计算神经科学数学建模编程深度前沿方向研究(下)
  • 医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(一)
  • 卷积神经网络CNN
  • Xposed框架实战指南:从原理到你的第一个模块
  • 面试之JVM
  • Java并发编程深度解析:从互斥锁到StampedLock的高性能锁优化之路
  • 计算机视觉:从 “看见” 到 “理解”,解锁机器感知世界的密码
  • 嵌入式(day34) http协议
  • 快速了解卷积神经网络
  • 【软考论文】论DevOps及其应用
  • C#由Dictionary不正确释放造成的内存泄漏问题与GC代系
  • 红黑树下探玄机:C++ mapmultimap 的幕后之旅
  • Java大厂面试实录:从Spring Boot到Kubernetes的全链路技术突围
  • 【数据结构】单链表详解