线程池自顶向下

news2025/4/3 5:56:32

在一些场景下,线程会被频繁创建和销毁,但他们却始终在完成相似的任务

这个场景下我们回去引入一个线程池的概念

可以简单总结为:

任务提交 → 核心线程执行 → 任务队列缓存 → 非核心线程执行 → 拒绝策略处理。

话不多说先看一个简单的线程池代码

通过 ThreadPoolExecutor 自定义(推荐)

先创建一个线程池

 
int corePoolSize = 5;           // 核心线程数
int maxPoolSize = 10;           // 最大线程数
long keepAliveTime = 60;        // 线程空闲时间
TimeUnit unit = TimeUnit.SECONDS; // 时间单位
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100); // 任务队列
ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,
    maxPoolSize,
    keepAliveTime,
    unit,
    workQueue,
    threadFactory,
    handler
);

提交线程池任务

// 提交Runnable任务
executor.execute(() -> {
    System.out.println("Task executed by " + Thread.currentThread().getName());
});
// 提交Callable任务(获取返回值)
Future<String> future = executor.submit(() -> {
    return "Result from Callable";
});
try {
    String result = future.get(); // 阻塞等待结果
    System.out.println(result);
} catch (Exception e) {
    e.printStackTrace();
}

但是在springboot的项目中我们一般不会像上面这样做,我们会像下面这样去做

这是一个项目结构

src/main/java
└── com.example.demo
    ├── AdminApplication.java (启动类)
    ├── config
    │   └── ExecutorConfig.java (线程池配置)
    ├── controller
    │   └── AsyncController.java
    └── service
        └── AsyncService.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication(scanBasePackages = {"com.example"})
@EnableAsync(proxyTargetClass = true) // 启用异步支持
public class AdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class, args);
    }
}

 

  1. YAML 配置文件 (application.yml)

async:
  executor:
    thread:
      core_pool_size: 5       # 核心线程数
      max_pool_size: 5         # 最大线程数
      queue_capacity: 99999    # 队列容量
      name:
        prefix: 异步执行线程池  # 线程名称前缀
  1. 线程池配置类

 
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@EnableAsync // 启用异步支持
public class ExecutorConfig {
    @Value("${async.executor.thread.core_pool_size}")
    private int corePoolSize;
    @Value("${async.executor.thread.max_pool_size}")
    private int maxPoolSize;
    @Value("${async.executor.thread.queue_capacity}")
    private int queueCapacity;
    @Value("${async.executor.thread.name.prefix}")
    private String namePrefix;
    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix(namePrefix + "-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

  1. 在 Service 层方法使用

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
    // 使用指定线程池执行异步方法
    @Async("asyncServiceExecutor") // 必须指定配置的线程池名称
    public void asyncMethod() {
        System.out.println("异步执行开始 - 线程名:" + Thread.currentThread().getName());
        try {
            // 模拟耗时操作
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("异步执行结束");
    }
}
  1. Controller 中调用异步方法

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
    private final AsyncService asyncService;
    public AsyncController(AsyncService asyncService) {
        this.asyncService = asyncService;
    }
    @GetMapping("/execute-async")
    public String executeAsync() {
        System.out.println("主线程开始处理请求 - 线程名:" + Thread.currentThread().getName());
        asyncService.asyncMethod(); // 触发异步执行
        System.out.println("主线程继续处理其他任务");
        return "异步任务已提交";
    }
}

这样我们就会去异步执行这个线程池的任务

但是线程池内部是怎么执行的呢

任务提交 → 核心线程执行 → 任务队列缓存 → 非核心线程执行 → 拒绝策略处理。

第一步,线程池通过 submit() 提交任务。

ExecutorService threadPool = Executors.newFixedThreadPool(5);threadPool.submit(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "办理业务");});

第二步,线程池会先创建核心线程来执行任务。

 

if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) { return; }}

第三步,如果核心线程都在忙,任务会被放入任务队列中。

 

workQueue.offer(task);

第四步,如果任务队列已满,且当前线程数量小于最大线程数,线程池会创建新的线程来处理任务。

 

if (!addWorker(command, false))

第五步,如果线程池中的线程数量已经达到最大线程数,且任务队列已满,线程池会执行拒绝策略。

 

handler.rejectedExecution(command, this);

线程池的参数

线程池有 7 个参数,需要重点关注的有核心线程数、最大线程数、等待队列、拒绝策略。

一、核心线程数(corePoolSize)

作用
  • 线程池常驻线程数量:即使空闲也不会被销毁(除非设置 allowCoreThreadTimeOut

  • 任务处理的基础保障

设置建议
场景类型推荐值原理说明
​CPU密集型CPU核数 + 1避免线程切换开销
​IO密集型CPU核数 × 2利用等待IO的时间处理其他任务
​混合型根据任务比例动态调整需监控CPU和IO等待时间
代码示例(Spring Boot)

 

async: executor: core-pool-size: 10 # CPU核数为4时,IO密集型设为8


二、最大线程数(maxPoolSize)

作用
  • 线程池扩容上限:应对突发流量高峰

  • 与核心线程数的差值决定弹性能力

设置建议
场景计算公式典型值
​秒杀场景maxPoolSize = corePoolSize × 250 → 100
​普通Web服务maxPoolSize = corePoolSize + 5020 → 70
​批处理任务maxPoolSize = 总任务数 / 单线程耗时按需计算
注意事项
  • 内存限制:每个线程占用约 1MB 栈空间,100线程需 100MB

  • JVM限制:通过 -Xss 调整栈大小(如 -Xss256k


三、等待队列(workQueue)

类型对比与选型
队列类型特性适用场景
​无界队列容量无限(LinkedBlockingQueue)任务量可控,防止OOM
​有界队列容量固定(ArrayBlockingQueue)严格控制内存使用
​同步移交队列容量0(SynchronousQueue)实时处理,拒绝策略配合使用

①、ArrayBlockingQueue:一个有界的先进先出的阻塞队列,底层是一个数组,适合固定大小的线程池。

②、LinkedBlockingQueue:底层是链表,如果不指定大小,默认大小是 Integer.MAX_VALUE,几乎相当于一个无界队列。

③、PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。任务按照其自然顺序或 Comparator 来排序。

适用于需要按照给定优先级处理任务的场景,比如优先处理紧急任务。

④、DelayQueue:类似于 PriorityBlockingQueue,由二叉堆实现的无界优先级阻塞队列。

Executors 中的 newScheduledThreadPool() 就使用了 DelayQueue 来实现延迟执行。

⑤、SynchronousQueue:每个插入操作必须等待另一个线程的移除操作,同样,任何一个移除操作都必须等待另一个线程的插入操作。

Executors.newCachedThreadPool() 就使用了 SynchronousQueue,这个线程池会根据需要创建新线程,如果有空闲线程则会重复使用,线程空闲 60 秒后会被回收。


四、拒绝策略(RejectedExecutionHandler)

策略对比与选择
策略行为使用场景
​AbortPolicy抛出异常(默认)需要快速失败场景
​CallerRunsPolicy提交线程执行任务控制提交速率,平滑削峰
​DiscardPolicy直接丢弃任务允许任务丢失(日志等场景)
​DiscardOldestPolicy丢弃最旧任务后重试实时性要求高场景
配置实践
// 自定义拒绝策略(记录日志并丢弃)
executor.setRejectedExecutionHandler(runnable -> {
    log.warn("Task rejected: {}", runnable);
});
// Spring Boot 配置示例
@Bean
public ThreadPoolTaskExecutor executor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    return executor;
}

五、参数联动配置方案

场景驱动配置模板
场景corePoolSizemaxPoolSizequeueCapacity拒绝策略
​电商秒杀50100100CallerRunsPolicy
​微服务API网关20501000AbortPolicy
​数据清洗服务1020无界队列DiscardOldestPolicy
​后台批处理48500DiscardPolicy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2326321.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用 Chrome devTools Source Override 实现JS逆向破解案例

之前讲解 Chrome 一大强势技术 override 时&#xff0c;给的案例貌似没有给大家留下多深的印象 浏览器本地替换&#xff08;local overrides&#xff09;快速定位前端样式问题的案例详解&#xff08;也是hook js的手段&#xff09;_浏览器的 overrides 替换功能-CSDN博客 其实…

容器C++ ——STL常用容器

string容器 string构造函数 #include<iostream> using namespace std; #include<string.h> void test01() {string s1;//默认构造const char* str "hello world";string s2(str);//传入char*cout << "s2" << s2 << endl;s…

npu踩坑记录

之前使用qwen系列模型在ascend 910a卡进行了一些生成任务, 贴出踩坑过程也许对遇到类似问题的同学有帮助: ) 目录 千问 qwq32环境配置 代码部署 生成内容清洗 已生成内容清洗 生成过程优化 Failed to initialize the HCCP process问题 assistant 的历史回答丢失 推理执…

Linux信号——信号的产生(1)

注&#xff1a;信号vs信号量&#xff1a;两者没有任何关系&#xff01; 信号是什么&#xff1f; Linux系统提供的&#xff0c;让用户&#xff08;进程&#xff09;给其他进程发送异步信息的一种方式。 进程看待信号的方式&#xff1a; 1.信号在没有发生的时候&#xff0c;进…

【机器学习】——机器学习思考总结

摘要 这篇文章深入探讨了机器学习中的数据相关问题&#xff0c;重点分析了神经网络&#xff08;DNN&#xff09;的学习机制&#xff0c;包括层级特征提取、非线性激活函数、反向传播和梯度下降等关键机制。同时&#xff0c;文章还讨论了数据集大小的标准、机器学习训练数据量的…

JMeter进行分布式压测

从机&#xff1a; 1、确认防火墙是否关闭&#xff1b; 2、打开网络设置&#xff0c;关闭多余端口&#xff1b;&#xff08;避免远程访问不到&#xff09; 3、打开JMeter/bin 目录底下的jmeter.properties&#xff1b; remove_hosts设置当前访问地址&#xff0c;192.XXXXX&…

快速入手-基于Django-rest-framework的第三方认证插件(SimpleJWT)权限认证扩展返回用户等其他信息(十一)

1、修改serializer.py&#xff0c;增加自定义类 # 自定义用户登录token等返回信息 class MyTokenObtainPair(TokenObtainPairView): def post(self, request, *args, **kwargs): serializer self.get_serializer(datarequest.data) try: serializer.is_valid(raise_exceptio…

关于IP免实名的那些事

IP技术已成为个人与企业保护隐私、提升网络效率的重要工具。其核心原理是通过中介服务器转发用户请求&#xff0c;隐藏真实IP地址&#xff0c;从而实现匿名访问、突破地域限制等目标。而“免实名”代理IP的出现&#xff0c;进一步简化了使用流程&#xff0c;用户无需提交身份信…

【SQL性能优化】预编译SQL:从注入防御到性能飞跃

&#x1f525; 开篇&#xff1a;直面SQL的"阿喀琉斯之踵" 假设你正在开发电商系统&#x1f6d2;&#xff0c;当用户搜索商品时&#xff1a; -- 普通SQL拼接&#xff08;危险&#xff01;&#xff09; String sql "SELECT * FROM products WHERE name "…

SQL Server从安装到入门一文掌握应用能力。

本篇文章主要讲解,SQL Server的安装教程及入门使用的基础知识,通过本篇文章你可以快速掌握SQL Server的建库、建表、增加、查询、删除、修改等基本数据库操作能力。 作者:任聪聪 日期:2025年3月31日 一、SQL Server 介绍: SQL Server 是微软旗下的一款主流且优质的数据库…

力扣HOT100之矩阵:54. 螺旋矩阵

这道题之前在代码随想录里刷过类似的&#xff0c;还有印象&#xff0c;我就按照当初代码随想录的思路做了一下&#xff0c;结果怎么都做不对&#xff0c;因为按照代码随想录的边界条件设置&#xff0c;当行数和列数都为奇数时&#xff0c;最后一个元素无法被添加到数组中&#…

5.1 WPF路由事件以及文本样式

一、路由事件 WPF中存在一种路由事件&#xff08;routed event&#xff09;&#xff0c;该事件将发送到包含该控件所在层次的所有控件&#xff0c;如果不希望继续向更高的方向传递&#xff0c;只要设置e.Handled true即可。 这种从本控件-->父控件->父的父控件的事件&am…

Python数据可视化-第1章-数据可视化与matplotlib

环境 开发工具 VSCode库的版本 numpy1.26.4 matplotlib3.10.1 ipympl0.9.7教材 本书为《Python数据可视化》一书的配套内容&#xff0c;本章为第1章 数据可视化与matplotlib 本文主要介绍了什么是数据集可视化&#xff0c;数据可视化的目的&#xff0c;常见的数据可视化方式…

Flutter敏感词过滤实战:基于AC自动机的高效解决方案

Flutter敏感词过滤实战&#xff1a;基于AC自动机的高效解决方案 在社交、直播、论坛等UGC场景中&#xff0c;敏感词过滤是保障平台安全的关键防线。本文将深入解析基于AC自动机的Flutter敏感词过滤实现方案&#xff0c;通过原理剖析实战代码性能对比&#xff0c;带你打造毫秒级…

Odoo/OpenERP 和 psql 命令行的快速参考总结

Odoo/OpenERP 和 psql 命令行的快速参考总结 psql 命令行选项 选项意义-a从脚本中响应所有输入-A取消表数据输出的对齐模式-c <查询>仅运行一个简单的查询&#xff0c;然后退出-d <数据库名>指定连接的数据库名&#xff08;默认为当前登录用户名&#xff09;-e回显…

Vue中使用antd-table组件时,树形表格展开配置不生效-defaultExpandedRowKeys-默认展开配置不生效

defaultExpandedRowKeys属性 defaultExpandAllRows这个属性仅仅是用来设置默认值的,只在第一次渲染的时候起作用,后续再去改变,无法实现响应式 解决方案一 a-table表格添加key属性,当每次获取值时,动态改变key,以达到重新渲染的效果 <a-table:key="tableKey"…

VRRP交换机三层架构综合实验

题目要求&#xff1a; 1&#xff0c;内网Ip地址使用172.16.0.0/16分配 说明可以划分多个子网&#xff0c;图中有2个VLAN&#xff0c;可以根据VLAN划分 2&#xff0c;sw1和SW2之间互为备份 互为备份通常通过VRRP&#xff08;虚拟路由冗余协议&#xff09;来实现。VRRP会在两个…

基于卷积神经网络的眼疾识别系统,resnet50,efficentnet(pytorch框架,python代码)

更多图像分类、图像识别、目标检测、图像分割等项目可从主页查看 功能演示&#xff1a; 眼疾识别系统resnet50&#xff0c;efficentnet&#xff0c;卷积神经网络&#xff08;pytorch框架&#xff0c;python代码&#xff09;_哔哩哔哩_bilibili &#xff08;一&#xff09;简介…

基于srpingboot智慧校园管理服务平台的设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

【力扣hot100题】(026)合并两个有序链表

可以创建一个新链表记录答案&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *…