Java常见技术分享-20-多线程安全-进阶模块-并发集合与线程池-ThreadPoolExecutor

简介

它是Java中具体的线程池实现类, 实现了ExecutorService接口。

它负责创建,复用, 销毁线程,让一个线程能重复执行多个任务, 而不必每次新建。 从而减少 新建 和 销毁线程的开销。

核心参数
  • 核心线程数(这里边的线程一直存在)
  • 最大线程数 (最多能创建的线程总数, 额外的线程数(就像临时员工 ), 当任务变少的时候, 空闲一段时间就会被销毁)
  • 空闲线程存活时间 (针对 额外的线程 , 如果超过这个存活时间 还没接受到任务 就自动销毁 )
  • 工作队列(存放暂时处理不了的任务 )
    • 有界队列 有个最大长度 , 队列满了, 就会新建 额外的线程, 当达到最大的线程数时, 就会 触发 拒绝策略
    • 无界队列, 超过核心线程数 处理的任务 直接放在 队列里边, 由于不会满, 所以出了核心线程数 ,不会创建新的 线程, 好处 是 不会触发拒绝策略, 坏处是 容易内存溢出, 应用崩溃。
核心流程

当一个任务提交到线程池时

  • 会判断当前运行的线程数 是否小于核心线程数
    • 如果是 直接创建一个核心线程来处理这个任务
    • 如果不是
      • 那么再判断 工作队列 是否已满
        • 如果没满 , 就放进去等待
        • 如果满了
          • 判断 当前线程数是否 小于最大线程数
          • 如果小于, 那么创建新的额外线程
          • 如果等于, 那么 就会触发拒绝策略
默认的四种拒绝策略
  • 直接抛出异常(RejectedExecutionException)
  • CallerRunsPolicy (主线程 会 直接阻塞式 的完成这个任务,再走后面的逻辑, 好处是不会丢任务)
  • DiscardPolicy (直接丢掉)
  • DiscardOldestPolicy (丢掉最旧的任务, 即会丢弃直接先提交的任务)
核心场景区分
  • CPU 密集型任务(像 视频编码, 复杂算法这种, 需要CPU一直高强度的工作, 因为CPU本身处理能力有限, 线程数太多, 反而会因为频繁的切换上下文, 导致效率下降, 所以这种场景 CPU不能太多 ),核心线程数 和 最大线程数(两个参数设置成一样 有一个好处是 避免频繁的创建和销毁非核心线程 带来的不稳定性) 通常设置为 CPU核心数的 1到2倍 。
  • IO 密集型任务 (像文件读写,网络请求这些, 线程经常处理等待状态, 这时候多开一些线程, 就能让CPU在等待的时间去处理别的任务, 提高整体效率, 核心线程数就可以设置的高一点) ,通常是CPU核心数的2到4倍

应用场景

  • Web服务器处理请求, 像Tomcat这类服务器, 每收到一个用户请求, 就会交给线程池里边的一个线程去处理。
  • 执行异步耗时任务, 比如审批流中的一个审批人审批完 ,给下一个审批人发送待办短信 通知 或者 邮件, 把他们交给线程池, 主线程 就不用等待这些任务的完成。
  • 批量处理任务, 比如需要批量处理大量的数据, 此时就可以 将数据 拆成很多小块, 让多个线程同时处理。 比如 导入一个大型文件, 在校验的时候, 就可以拆成很多个部分, 并行进行校验, 节省时间。
相关推荐
侠客行031710 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪11 小时前
深入浅出LangChain4J
java·langchain·llm
灰子学技术12 小时前
go response.Body.close()导致连接异常处理
开发语言·后端·golang
老毛肚12 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎13 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
二十雨辰13 小时前
[python]-AI大模型
开发语言·人工智能·python
Yvonne爱编码13 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚13 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂13 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
pas13613 小时前
41-parse的实现原理&有限状态机
开发语言·前端·javascript