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

SpringBoot线程池的使用

SpringBoot线程池的使用

在现代Web应用开发中,特别是在使用Spring Boot框架时,合理使用线程池可以显著提高应用的性能和响应速度。线程池不仅能够减少线程创建和销毁的开销,还能有效地控制并发任务的数量,避免因线程过多而导致的系统资源耗尽。本文将详细介绍如何在Spring Boot中配置和使用线程池,并提供一些示例。

1. 线程池的基本概念

线程池是一种管理和复用线程的机制。它预先创建一定数量的线程,当有任务需要执行时,可以从池中取出线程来处理,处理完后再将线程返回池中。这样可以避免频繁创建和销毁线程带来的性能开销。

线程池的意义在于:

  1. 提高响应速度:通过复用已存在的线程,可以立即开始执行任务,而不需要等待新线程的创建。
  2. 控制资源消耗:通过设定线程池的最大大小,可以避免因创建过多线程而耗尽系统资源。
  3. 管理线程生命周期:线程池负责管理线程的生命周期,包括创建、分配任务、回收等,使开发者能够专注于业务逻辑的实现。
  4. 优化系统性能:合理配置线程池参数,可以提高系统的并发处理能力和整体性能。

2. Spring Boot中的线程池配置

在Spring Boot中,可以通过配置类来创建和管理线程池。Spring Boot提供了ThreadPoolTaskExecutor类来封装Java标准库中的ThreadPoolExecutor,使得配置更加简单和灵活。

2.1 创建线程池配置类

首先,创建一个配置类来定义线程池的配置。这个配置类需要使用@Configuration@EnableAsync注解,表示这是一个配置类并且启用了异步支持。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
@EnableAsync
public class ThreadPoolConfig {/*** 创建自定义线程池* @return ThreadPoolTaskExecutor 线程池实例*/@Bean(name = "customThreadPool")public ThreadPoolTaskExecutor customThreadPool() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 核心线程数:线程池中始终保留的线程数量executor.setCorePoolSize(5);// 最大线程数:线程池允许的最大线程数executor.setMaxPoolSize(10);// 队列容量:线程池所使用的任务队列大小executor.setQueueCapacity(20);// 线程存活时间:非核心线程闲置超过此时间后会被回收executor.setKeepAliveSeconds(30);// 线程名前缀:用于区分线程池中的线程executor.setThreadNamePrefix("custom-thread-");// 拒绝策略:当线程池无法接受新任务时的应对策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 初始化线程池executor.initialize();return executor;}
}

在这个例子中,我们设置了线程池的核心线程数、最大线程数、队列容量、线程存活时间、线程名前缀和拒绝策略。这些参数可以根据具体的应用场景进行调整。

2.2 配置参数详解

  • 核心线程数 (corePoolSize):线程池中始终保留的线程数量,即使它们处于空闲状态。当有新任务提交时,优先由核心线程执行。
  • 最大线程数 (maxPoolSize):线程池允许的最大线程数。当核心线程满载且任务队列已满时,线程池会创建额外的非核心线程来处理任务,直到达到此上限。
  • 队列容量 (queueCapacity):线程池所使用的任务队列大小。当核心线程全部忙碌时,新任务会被放入队列等待执行。队列类型可选,如无界队列、有界队列(如ArrayBlockingQueue)、优先级队列(如PriorityBlockingQueue)等。
  • 线程存活时间 (keepAliveSeconds):非核心线程闲置超过此时间后会被回收。设置为0表示非核心线程随用随创建,随空随销毁。
  • 拒绝策略 (rejectedExecutionHandler):当线程池无法接受新任务时(例如队列已满且线程数达到最大值),采取的应对策略,如AbortPolicy(抛出异常)、CallerRunsPolicy(调用者线程执行任务)、DiscardPolicy(丢弃任务)和DiscardOldestPolicy(丢弃队列中最旧的任务)等。

3. 使用线程池执行任务

配置好线程池后,可以通过注入ThreadPoolTaskExecutor实例,调用其executesubmit方法来提交任务。

3.1 创建服务类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;import java.util.concurrent.Callable;
import java.util.concurrent.Future;@Service
public class AsyncService {@Autowired@Qualifier("customThreadPool")private ThreadPoolTaskExecutor taskExecutor;/*** 执行异步任务* @param task 要执行的任务*/public void executeAsyncTask(Runnable task) {taskExecutor.execute(task);}/*** 提交异步任务并返回结果* @param task 要执行的任务* @return 任务的结果*/public Future<String> submitAsyncTask(Callable<String> task) {return taskExecutor.submit(task);}
}

在这个例子中,我们定义了一个服务类AsyncService,并通过@Autowired注解注入了之前配置的线程池。然后,我们定义了两个方法executeAsyncTasksubmitAsyncTask来分别提交Runnable任务和Callable任务。

3.2 使用示例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.concurrent.Future;@Component
public class AsyncTaskRunner {@Autowiredprivate AsyncService asyncService;/*** 触发异步任务*/public void triggerAsyncTasks() {Runnable task1 = () -> System.out.println("Executing task 1 in thread: " + Thread.currentThread().getName());asyncService.executeAsyncTask(task1);Callable<String> task2 = () -> {Thread.sleep(2000); // 模拟耗时操作return "Task 2 result";};Future<String> futureResult = asyncService.submitAsyncTask(task2);// 异步获取结果try {String result = futureResult.get();System.out.println("Task 2 returned: " + result);} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,我们定义了一个AsyncTaskRunner类,用于触发异步任务。我们创建了两个任务task1task2,并通过AsyncService类提交这些任务。task2的结果可以通过Future对象异步获取。

4. 使用@Async注解

如果希望某个方法异步执行,可以在方法上添加@Async注解,并确保在启动类上添加了@EnableAsync注解。

4.1 创建异步服务类

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;import java.util.concurrent.Future;@Service
public class AsyncServiceImpl {/*** 异步执行任务* @return 任务的结果* @throws InterruptedException 如果任务被中断*/@Async("customThreadPool")public Future<String> executeAsync() throws InterruptedException {Thread.sleep(2000); // 模拟耗时操作return new AsyncResult<>("Task completed");}
}

在这个例子中,executeAsync方法被标记为异步方法,它将在customThreadPool线程池中执行。

4.2 调用异步方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.concurrent.Future;@Component
public class AsyncTaskRunner {@Autowiredprivate AsyncServiceImpl asyncService;/*** 触发异步任务*/public void triggerAsyncTask() {Future<String> result = asyncService.executeAsync();try {System.out.println("Task result: " + result.get());} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,我们调用了异步方法executeAsync,并使用Future对象异步获取任务结果。

5. 监控线程池

Spring Boot对线程池的监控主要依赖于Micrometer库(如果已集成)。可以通过/actuator/metrics/threadpool.*端点获取线程池各项指标,如活跃线程数、队列大小、已完成任务数等。结合Prometheus、Grafana等工具,可以构建实时监控面板,以便及时发现和调整线程池性能瓶颈。

6. 常见问题与注意事项

  • 线程池参数调优:应根据实际业务负载动态调整线程池参数。这可能需要结合日志分析、监控数据及压测结果,确保线程池既能充分利用系统资源,又能避免过度竞争导致性能下降或系统不稳定。
  • 线程安全:在多线程环境中,确保共享资源的线程安全性是非常重要的。可以使用锁、原子变量等机制来保证线程安全。
  • 异常处理:在异步任务中,需要注意异常处理,防止异常未被捕获而导致任务失败。

总结

通过合理配置和使用线程池,Spring Boot应用可以更好地处理并发任务,提高系统的性能和响应速度。配置线程池时,需要根据具体的业务场景选择合适的参数,如核心线程数、最大线程数、队列容量等。同时,还需要考虑任务的性质,选择合适的拒绝策略来处理超出线程池处理能力的任务。

相关文章:

SpringBoot线程池的使用

SpringBoot线程池的使用 在现代Web应用开发中&#xff0c;特别是在使用Spring Boot框架时&#xff0c;合理使用线程池可以显著提高应用的性能和响应速度。线程池不仅能够减少线程创建和销毁的开销&#xff0c;还能有效地控制并发任务的数量&#xff0c;避免因线程过多而导致的…...

Neural Magic 发布 LLM Compressor:提升大模型推理效率的新工具

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

HttpServletRequest req和前端的关系,req.getParameter详细解释,req.getParameter和前端的关系

HttpServletRequest 对象在后端和前端之间起到了桥梁的作用&#xff0c;它包含了来自客户端的所有请求信息。通过 HttpServletRequest 对象&#xff0c;后端可以获取前端发送的请求参数、请求头、请求方法等信息&#xff0c;并根据这些信息进行相应的处理。以下是对 HttpServle…...

React-useEffect的使用

useEffect react提供的一个常用hook&#xff0c;用于在函数组件中执行副作用操作&#xff0c;比如数据获取、订阅或手动更改DOM。 基本用法&#xff1a; 接受2个参数&#xff1a; 一个包含命令式代码的函数&#xff08;副作用函数&#xff09;。一个依赖项数组&#xff0c;用…...

MySQL数据库与Informix:能否创建同名表?

MySQL数据库与Informix:能否创建同名表? 一、MySQL数据库中的同名表创建1. 使用CREATE TABLE ... SELECT语句2. 使用CREATE TABLE LIKE语句3. 复制表结构并选择性复制数据4. 使用同义词(Synonym)二、Informix数据库中的同名表创建1. 使用不同所有者2. 使用不同模式3. 复制表…...

爬虫实战:采集知乎XXX话题数据

目录 反爬虫的本意和其带来的挑战目标实战开发准备代码开发发现问题1. 发现问题[01]2. 发现问题[02] 解决问题1. 解决问题[01]2. 解决问题[02] 最终结果 结语 反爬虫的本意和其带来的挑战 在这个数字化时代社交媒体已经成为人们表达观点的重要渠道&#xff0c;对企业来说&…...

大数据新视界 -- Hive 数据桶原理:均匀分布数据的智慧(上)(9/ 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…...

【小白学机器学习33】 大数定律python的 pandas.Dataframe 和 pandas.Series基础内容

目录 0 总结 0.1pd.Dataframe有一个比较麻烦琐碎的地方&#xff0c;就是引号 和括号 0.2 pd.Dataframe关于括号的原则 0.3 分清楚几个数据类型和对应的方法的范围 0.4 几个数据结构的构造关系 list → np.array(list) → pd.Series(np.array)/pd.Dataframe 1 python 里…...

【shodan】(五)网段利用

shodan基础&#xff08;五&#xff09; 声明&#xff1a;该笔记为up主 泷羽的课程笔记&#xff0c;本节链接指路。 警告&#xff1a;本教程仅作学习用途&#xff0c;若有用于非法行为的&#xff0c;概不负责。 nsa ip address range www.nsa.gov需科学上网 搜索网段 shodan s…...

LeetCode739. 每日温度(2024冬季每日一题 15)

给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 示例 1: 输入: temperatu…...

Node.js的http模块:创建HTTP服务器、客户端示例

新书速览|Vue.jsNode.js全栈开发实战-CSDN博客 《Vue.jsNode.js全栈开发实战&#xff08;第2版&#xff09;&#xff08;Web前端技术丛书&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 要使用http模块&#xff0c;只需要在文件中通过require(http)引入即可。…...

加菲工具 - 好用免费的在线工具集合

加菲工具 https://orcc.online AI 工具 加菲工具 集合了目前主流的&#xff0c;免费可用的ai工具 文档处理 加菲工具 pdf转word、office与pdf互转等等工具都有链接 图片图标 加菲工具 统计了好用免费的在线工具 编码解码 加菲工具 base64编码解码、url编码解码、md5计算…...

.NET9 - 新功能体验(二)

书接上回&#xff0c;我们继续来聊聊.NET9和C#13带来的新变化。 01、新的泛型约束 allows ref struct 这是在 C# 13 中&#xff0c;引入的一项新的泛型约束功能&#xff0c;允许对泛型类型参数应用 ref struct 约束。 可能这样说不够直观&#xff0c;简单来说就是Span、ReadO…...

map和redis关系

Map 和 Redis 都是用于存储和管理数据的工具&#xff0c;但它们在用途、实现和应用场景上有所不同。下面详细解释 Map 和 Redis 之间的关系和区别。 1. Map 数据结构 定义 Map 是一种数据结构&#xff0c;用于存储键值对&#xff08;key-value pairs&#xff09;。每个键都是…...

《数据结构》学习系列——图(中)

系列文章目录 目录 图的遍历深度优先遍历递归算法堆栈算法 广度优先搜索 拓扑排序定义定理算法思想伪代码 关键路径基本概念关键活动有关量数学公式伪代码时间复杂性 图的遍历 从给定连通图的某一顶点出发&#xff0c;沿着一些边访问遍图中所有的顶点&#xff0c;且使每个顶点…...

探索Python的HTTP之旅:揭秘Requests库的神秘面纱

文章目录 **探索Python的HTTP之旅&#xff1a;揭秘Requests库的神秘面纱**第一部分&#xff1a;背景介绍第二部分&#xff1a;Requests库是什么&#xff1f;第三部分&#xff1a;如何安装Requests库&#xff1f;第四部分&#xff1a;Requests库的五个简单函数使用方法第五部分&…...

Python 爬虫从入门到(不)入狱学习笔记

爬虫的流程&#xff1a;从入门到入狱 1 获取网页内容1.1 发送 HTTP 请求1.2 Python 的 Requests 库1.2 实战&#xff1a;豆瓣电影 scrape_douban.py 2 解析网页内容2.1 HTML 网页结构2.2 Python 的 Beautiful Soup 库 3 存储或分析数据&#xff08;略&#xff09; 一般爬虫的基…...

IDEA优雅debug

目录 引言一、断点分类&#x1f384;1.1 行断点1.2 方法断点1.3 属性断点1.4 异常断点1.5 条件断点1.6 源断点1.7 多线程断点1.8 Stream断点 二、调试动作✨三、Debug高级技巧&#x1f389;3.1 watch3.2 设置变量3.3 异常抛出3.4 监控JVM堆大小3.5 数组过滤和筛选 引言 使用ID…...

wp the_posts_pagination 与分类页面搭配使用

<ul> <?php while( have_posts() ) : the_post(); <li > <a href"<?php the_permalink(); ?>"> <?php xizhitbu_get_thumbnail(thumb-pro); ?> </a> <p > <a href&q…...

大数据-231 离线数仓 - DWS 层、ADS 层的创建 Hive 执行脚本

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决

问题&#xff1a; pgsql数据库通过备份数据库文件进行还原时&#xff0c;如果表中有自增序列&#xff0c;还原后可能会出现重复的序列&#xff0c;此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”&#xff0c;…...

高抗扰度汽车光耦合器的特性

晶台光电推出的125℃光耦合器系列产品&#xff08;包括KL357NU、KL3H7U和KL817U&#xff09;&#xff0c;专为高温环境下的汽车应用设计&#xff0c;具备以下核心优势和技术特点&#xff1a; 一、技术特性分析 高温稳定性 采用先进的LED技术和优化的IC设计&#xff0c;确保在…...