Spring Boot 异步编程

文章目录

    • 一、异步方法的使用
      • 1. 开启异步支持
      • 2. 定义异步方法
      • 3. 调用异步方法
      • 踩坑记录
      • 心得体会
    • 二、线程池配置
      • 1. 自定义线程池
      • 2. 使用自定义线程池
      • 踩坑记录
      • 心得体会
    • 三、异步任务的监控与管理
      • 1. 日志记录
      • 2. 异常处理
      • 3. 线程池监控
      • 踩坑记录
      • 心得体会

在现代应用程序开发中,异步编程是提升系统性能和响应能力的重要手段。Spring Boot 提供了便捷的方式来实现异步编程,下面将详细介绍异步方法的使用、线程池配置以及异步任务的监控与管理。

一、异步方法的使用

1. 开启异步支持

在 Spring Boot 主应用类上添加 @EnableAsync 注解,开启 Spring 的异步方法执行功能。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync
public class AsyncApp {public static void main(String[] args) {SpringApplication.run(AsyncApp.class, args);}
}

2. 定义异步方法

在需要异步执行的方法上添加 @Async 注解。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {@Asyncpublic CompletableFuture<String> asyncTask() {try {// 模拟耗时操作Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return CompletableFuture.completedFuture("异步任务执行完成");}
}

3. 调用异步方法

在控制器或者其他服务类中注入包含异步方法的服务类,并调用异步方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;@RestController
public class AsyncController {@Autowiredprivate AsyncService asyncService;@GetMapping("/async")public String asyncCall() throws InterruptedException, ExecutionException {CompletableFuture<String> future = asyncService.asyncTask();// 可以在此处执行其他操作// 等待异步任务完成并获取结果return future.get();}
}

踩坑记录

  • 注解未生效:若 @EnableAsync 未添加到主应用类,或者异步方法所在类未被 Spring 管理(如未加 @Service 等注解),@Async 注解将不生效。此外,若在同一类中直接调用异步方法,而非通过 Spring 代理对象调用,也不会异步执行,因为 Spring 的 AOP 代理机制基于代理对象。
  • 返回值处理不当:有返回值的异步方法需用 CompletableFuture 包装,若直接返回普通类型,调用 get() 方法获取结果时可能阻塞或抛异常。

心得体会

要深刻理解 Spring 的 AOP 代理机制对 @Async 注解的影响,设计代码时尽量通过依赖注入和代理对象调用异步方法。同时,对于有返回值的异步方法,务必使用 CompletableFuture 包装,并妥善处理 get() 方法可能抛出的异常。

二、线程池配置

1. 自定义线程池

默认情况下,Spring Boot 使用简单线程池执行异步任务。可通过创建配置类,使用 ThreadPoolTaskExecutor 自定义线程池。

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;@Configuration
@EnableAsync
public class AsyncConfig {@Bean(name = "customAsyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 核心线程数executor.setCorePoolSize(5);// 最大线程数executor.setMaxPoolSize(10);// 队列容量executor.setQueueCapacity(25);// 线程名前缀executor.setThreadNamePrefix("CustomAsyncThread-");// 线程池关闭时等待所有任务完成executor.setWaitForTasksToCompleteOnShutdown(true);// 等待任务完成的时间executor.setAwaitTerminationSeconds(60);// 初始化线程池executor.initialize();return executor;}
}

2. 使用自定义线程池

@Async 注解中指定使用自定义线程池的名称。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {@Async("customAsyncExecutor")public CompletableFuture<String> asyncTask() {try {Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}return CompletableFuture.completedFuture("异步任务执行完成");}
}

踩坑记录

  • 参数设置不合理:核心线程数、最大线程数和队列容量设置需根据业务场景调整。核心线程数过小,任务处理不及时;最大线程数过大,占用过多系统资源。队列容量过小,新任务可能被拒绝;过大则可能导致任务堆积,影响系统响应时间。
  • 未正确初始化:配置线程池时,若忘记调用 executor.initialize() 方法,线程池可能无法正常工作,导致异步任务无法执行或执行过程中出现异常。

心得体会

配置线程池时,要充分考虑业务特点和系统资源情况。对于 I/O 密集型任务,可适当增大核心线程数;对于 CPU 密集型任务,核心线程数可相对较小。同时,务必确保调用 initialize() 方法初始化线程池。

三、异步任务的监控与管理

1. 日志记录

在异步方法中添加日志记录,跟踪任务执行过程。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;import java.util.concurrent.CompletableFuture;@Service
public class AsyncService {private static final Logger logger = LoggerFactory.getLogger(AsyncService.class);@Async("customAsyncExecutor")public CompletableFuture<String> asyncTask() {logger.info("异步任务开始执行");try {Thread.sleep(2000);} catch (InterruptedException e) {logger.error("异步任务被中断", e);Thread.currentThread().interrupt();}logger.info("异步任务执行完成");return CompletableFuture.completedFuture("异步任务执行完成");}
}

2. 异常处理

实现 AsyncUncaughtExceptionHandler 接口处理异步方法中抛出的未捕获异常。

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {@Overridepublic void handleUncaughtException(Throwable throwable, Method method, Object... objects) {System.err.println("异步方法 " + method.getName() + " 抛出未捕获异常");for (Object param : objects) {System.err.println("参数: " + param);}throwable.printStackTrace();}
}

在配置类中配置异常处理器:

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {@Bean(name = "customAsyncExecutor")public Executor asyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("CustomAsyncThread-");executor.setWaitForTasksToCompleteOnShutdown(true);executor.setAwaitTerminationSeconds(60);executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new CustomAsyncExceptionHandler();}
}

3. 线程池监控

通过 ThreadPoolTaskExecutor 提供的方法获取线程池状态信息。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;@Service
public class ThreadPoolMonitorService {@Autowiredprivate ThreadPoolTaskExecutor customAsyncExecutor;public int getActiveThreadCount() {return customAsyncExecutor.getActiveCount();}public int getQueueSize() {return customAsyncExecutor.getThreadPoolExecutor().getQueue().size();}
}

踩坑记录

  • 日志记录不详细:若日志信息不够详细,排查问题时会遇到困难。例如,只记录任务开始和结束信息,未记录关键步骤执行情况和异常信息,难以定位问题。
  • 异常处理不全面:实现 AsyncUncaughtExceptionHandler 接口时,若未全面处理异常,可能导致部分异常信息丢失。

心得体会

在异步方法中添加详细日志记录,包括任务开始、关键步骤、异常信息等,以便出现问题时能快速定位。实现异常处理器时,要尽可能全面记录异常信息,为问题排查和修复提供有力支持。

总之,Spring Boot 异步编程能显著提升系统性能和响应能力,但实际使用中需注意各种细节,避免踩坑。通过不断实践和总结经验,才能更好地掌握异步编程技巧。

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

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

相关文章

0.大模型开发知识点需求综述

文章目录 一、机器学习与深度学习基础二、自然语言处理&#xff08;NLP&#xff09;基础三、大模型架构四、训练优化技术五、数据处理与预处理六、分布式训练与并行化策略七、微调方法与参数高效微调八、训练框架、工具与自动化流程九、评估与部署十、前沿技术与未来趋势 已更新…

docker目录挂载与卷映射的区别

在 Docker 中&#xff0c;目录挂载&#xff08;Bind Mount&#xff09;和卷映射&#xff08;Volume Mount&#xff09;的命令语法差异主要体现在路径格式上&#xff0c;具体表现为是否以斜杠&#xff08;/&#xff09;开头。以下是两者的核心区别及使用场景的总结&#xff1a; …

[Java基础-线程篇]7_线程设计模式与总结

摘要&#xff1a;懒汉单例模式怎么变得线程安全&#xff1f;Master-Worker归并模式&#xff0c;工作窃取算法。Java线程相关源码使用了什么设计模式&#xff1f; 资料引用&#xff1a;《Java高并发核心编程卷2》 目录 线程安全的单例模式 Master-Worker模式 工作窃取算法 …

在【k8s】中部署Jenkins的实践指南

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Jenkins简介 2、k8s简介 3、什么在…

代码随想录算法营Day59 | 寻找存在的路径, 冗余连接,冗余连接II

寻找存在的路径 这题使用并查集即可。并查集加路径压缩。 #include <iostream> using namespace std; int find(int* father,int u){return father[u] u ? u : father[u] find(father,father[u]); }bool isSame(int* father,int u,int v){return find(father,u) fi…

正则表达式(2)匹配规则

正则表达式的匹配规则定义了如何识别字符串中的特定模式。这些规则包括字符类匹配、元字符匹配、数量词、字符转义和分组。 字符类匹配 字符类匹配允许你指定一个字符集合&#xff0c;并匹配该集合中的任意单个字符。这是通过方括号 [] 来实现的。 简单字符类&#xff1a;[abc…

【QWEN】机器人控制器的控制周期越短精度越高吗

好的&#xff0c;用户问的是“机器人控制器的控制周期越短精度越高吗”。我需要根据提供的知识库内容来回答这个问题。首先&#xff0c;我得回忆一下知识库里的相关信息。 知识库里有几篇相关的文章。比如&#xff0c;[3]提到控制周期越短&#xff0c;控制性能的上限越高&…

[总概]Vue2/3React Diff算法

根据搜索结果,大部分文档都详细描述了Vue的Diff算法原理、优化策略以及实现细节。例如,网页1详细介绍了Vue Diff算法的核心设计,包括双端比较和key的作用;Vue3中的快速Diff算法; 通常,解释一个算法可以从其基本原理、核心策略、优化手段、源码实现以及应用场景等方面展开…

【MySQL_03】数据库基本--核心概念

文章目录 一、数据库基础1.1 数据库基础定义1.2 数据库分类与典型产品1.3 数据库模型1.4 数据库层次结构1.5 数据库核心机制1.6 数据表和视图1.61 数据表&#xff08;Table&#xff09;1.62 视图&#xff08;View&#xff09; 1.7 键类型1.8 MySQL数据类型1.9 数据库范式化 二、…

FreeRTOS第16篇:FreeRTOS链表实现细节04_为什么FreeRTOS选择“侵入式链表”

文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 1 传统链表 vs. 侵入式链表 在嵌入式系统中,内存和性能的优化至关重要。FreeRTOS选择侵入式链表而非传统链表,其背后是内…

STM32读写片内FLASH 笔记

文章目录 前言STM32F105的内部ROM分布STM32F10x的闪存擦写解锁FPECMain FLASH 的编写 main Flash的擦除注意点 前言 在通过OTA的方式对设备进行升级&#xff0c;若在使用内部FLASH装载固件程序的方式下&#xff0c;需要擦写 内部FLASH 从而实现把新的固件程序写入到 内部FLASH…

Python爬虫实战:爬取财金网实时财经信息

注意:以下内容仅供技术研究,请遵守目标网站的robots.txt规定,控制请求频率避免对目标服务器造成过大压力! 一、引言 在当今数字化时代,互联网数据呈爆炸式增长,其中蕴含着巨大的商业价值、研究价值和社会价值。从金融市场动态分析到行业趋势研究,从舆情监测到学术信息收…

3.3.2 用仿真图实现点灯效果

文章目录 文章介绍Keil生成.hex代码Proteus仿真图中导入.hex代码文件开始仿真 文章介绍 点灯之前需要准备好仿真图keil代码 仿真图参考前文&#xff1a;3.3.2 Proteus第一个仿真图 keil安装参考前文&#xff1a;3.1.2 Keil4安装教程 keil新建第一个项目参考前文&#xff1a;3.1…

996引擎-问题处理:实现自定义道具变身卡

996引擎-问题处理:实现自定义道具变身卡 方案一、修改角色外观(武器、衣服、特效) 实现变身先看效果创建个NPC测试效果方案二、利用 Buff 实现变身创建:变身Buff配buff表,实现人物变形测试NPC创建道具:变身卡配item表,添加道具:变身卡触发函数参考资料方案一、修改角色外…

AI视频领域的DeepSeek—阿里万相2.1图生视频

让我们一同深入探索万相 2.1 &#xff0c;本文不仅介绍其文生图和文生视频的使用秘籍&#xff0c;还将手把手教你如何利用它实现图生视频。 如下为生成的视频效果&#xff08;我录制的GIF动图&#xff09; 如下为输入的图片 目录 1.阿里巴巴全面开源旗下视频生成模型万相2.1模…

驱动 AI 边缘计算新时代!高性能 i.MX 95 应用平台引领未来

智慧浪潮崛起&#xff1a;AI与边缘计算的时代 正悄然深植于我们的日常生活之中&#xff0c;无论是火热的 ChatGPT 与 DeepSeek 语言模型&#xff0c;亦或是 Meta 智能眼镜&#xff0c;AI 技术已经无形地影响着我们的生活。这股变革浪潮并未停歇&#xff0c;而是进一步催生了更高…

如何快速判断IP是否为代理

1.探究IP地址的地理分布 代理IP的所在位置&#xff0c;往往与用户实际所在地不吻合。可以通过运用WHOIS查询工具或在线IP地址定位服务&#xff0c;输入所需查询的IP&#xff0c;即可获得其地理位置信息。 若该信息显示的位置并非用户所在城市或显示为知名代理服务器节点&…

从CL1看生物计算机的创新突破与发展前景:技术、应用与挑战的多维度剖析

一、引言 1.1 研究背景与意义 随着科技的飞速发展&#xff0c;计算机技术已经成为推动现代社会进步的核心力量之一。从最初的电子管计算机到如今的大规模集成电路计算机&#xff0c;计算机的性能得到了极大的提升&#xff0c;应用领域也不断拓展。然而&#xff0c;传统计算机…

AI革命先锋:DeepSeek与蓝耘通义万相2.1的无缝融合引领行业智能化变革

云边有个稻草人-CSDN博客 目录 引言 一、什么是DeepSeek&#xff1f; 1.1 DeepSeek平台概述 1.2 DeepSeek的核心功能与技术 二、蓝耘通义万相2.1概述 2.1 蓝耘科技简介 2.2 蓝耘通义万相2.1的功能与优势 1. 全链条智能化解决方案 2. 强大的数据处理能力 3. 高效的模型…

zabbix图表中文显示方框

问题&#xff1a; zabbix安装完成后&#xff0c;查看图形&#xff0c;下方中文显示为方框 思路&#xff1a; 替换字体文件&#xff0c;或者修改配置文件指向中文可以正常显示的字体文件 方案&#xff1a; 查找资料确认影响因素 通过资料查询得知&#xff0c;使用的字体文…