SpringBoot异步方法支持注解@Async应用

SpringBoot异步方法支持注解@Async应用

1.为什么需要异步方法?

合理使用异步方法可以有效的提高执行效率

同步执行(同在一个线程中):图片

异步执行(开启额外线程来执行):
图片

2.SpringBoot中的异步方法支持

在SpringBoot中并不需要我们自己去创建维护线程或者线程池来异步的执行方法, SpringBoot已经提供了异步方法支持注解.

@EnableAsync // 使用异步方法时需要提前开启(在启动类上或配置类上)
@Async // 被async注解修饰的方法由SpringBoot默认线程池(SimpleAsyncTaskExecutor)执行

service层:

@Service
public class ArticleServiceImpl {// 查询文章public String selectArticle() {//  模拟文章查询操作System.out.println("查询任务线程"+Thread.currentThread().getName());return "文章详情";}// 文章阅读量+1@Asyncpublic void updateReadCount() {try {// 模拟耗时操作Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("更新任务线程"+Thread.currentThread().getName());}
}

controller层:

@RestController
public class AsyncTestController {@Autowiredprivate ArticleServiceImpl articleService;/*** 模拟获取文章后阅读量+1*/@GetMapping("/article")public String getArticle() {long start = System.currentTimeMillis();// 查询文章String article = articleService.selectArticle();// 阅读量+1articleService.updateReadCount();long end = System.currentTimeMillis();System.out.println("文章阅读业务执行完毕,执行共计耗时:"+(end-start));return article;}}

测试结果: 我们可以感受到接口响应速度大大提升, 而且从日志中key看到两个执行任务是在不同的线程中执行的

查询任务线程http-nio-8800-exec-3
文章阅读业务执行完毕,执行共计耗时:56
更新任务线程task-1

3.自定义线程池执行异步方法

SpringBoot为我们默认提供了线程池(SimpleAsyncTaskExecutor)来执行我们的异步方法, 我们也可以自定义自己的线程池.

第一步配置自定义线程池

@EnableAsync // 开启多线程, 项目启动时自动创建
@Configuration
public class AsyncConfig {@Bean("customExecutor")public ThreadPoolTaskExecutor asyncOperationExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(8);// 设置最大线程数executor.setMaxPoolSize(20);// 设置队列大小executor.setQueueCapacity(Integer.MAX_VALUE);// 设置线程活跃时间(秒)executor.setKeepAliveSeconds(60);// 设置线程名前缀+分组名称executor.setThreadNamePrefix("AsyncOperationThread-");executor.setThreadGroupName("AsyncOperationGroup");// 所有任务结束后关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);// 初始化executor.initialize();return executor;}
}

第二步, 在@Async注解上指定执行的线程池即可

// 文章阅读量+1
@Async("customExecutor")
public void updateReadCount() {// TODO 模拟耗时操作try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("更新文章阅读量线程"+Thread.currentThread().getName());
}

测试结果:

查询任务线程http-nio-8800-exec-1
文章阅读业务执行完毕,执行共计耗时:17
更新任务线程AsyncOperationThread-1

4.如何捕获(无返回值的)异步方法中的异常

以实现AsyncConfigurer接口的getAsyncExecutor方法和getAsyncUncaughtExceptionHandler方法改造配置类

自定义异常处理类CustomAsyncExceptionHandler

@EnableAsync // 开启多线程, 项目启动时自动创建
@Configuration
public class AsyncConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();// 设置核心线程数executor.setCorePoolSize(8);// 设置最大线程数executor.setMaxPoolSize(20);// 设置队列大小executor.setQueueCapacity(Integer.MAX_VALUE);// 设置线程活跃时间(秒)executor.setKeepAliveSeconds(60);// 设置线程名前缀+分组名称executor.setThreadNamePrefix("AsyncOperationThread-");executor.setThreadGroupName("AsyncOperationGroup");// 所有任务结束后关闭线程池executor.setWaitForTasksToCompleteOnShutdown(true);// 初始化executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new CustomAsyncExceptionHandler();}
}
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {@Overridepublic void handleUncaughtException(Throwable throwable, Method method, Object... obj) {System.out.println("异常捕获---------------------------------");System.out.println("Exception message - " + throwable.getMessage());System.out.println("Method name - " + method.getName());for (Object param : obj) {System.out.println("Parameter value - " + param);}System.out.println("异常捕获---------------------------------");}}

测试结果:

查询任务线程http-nio-8800-exec-1
文章阅读业务执行完毕,执行共计耗时:20
异常捕获---------------------------------
Exception message - / by zero
Method name - updateReadCount
异常捕获---------------------------------

5.如何获取(有返回值)异步方法的返回值

使用Future类及其子类来接收异步方法返回值

注意:

  • 无返回值的异步方法抛出异常不会影响Controller的主要业务逻辑
  • 有返回值的异步方法抛出异常会影响Controller的主要业务逻辑
// 异步方法---------------------------------------------------------------------
@Async
public CompletableFuture<Integer> updateReadCountHasResult() {try {// 模拟耗时操作Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("更新文章阅读量线程"+Thread.currentThread().getName());return CompletableFuture.completedFuture(100 + 1);
}// Controller调用---------------------------------------------------------------------
@GetMapping("/article")
public String getArticle() throws ExecutionException, InterruptedException {// 查询文章String article = articleService.selectArticle();// 阅读量+1CompletableFuture<Integer> future = articleService.updateReadCountHasResult();int count = 0;// 循环等待异步请求结果while (true) {if(future.isCancelled()) {System.out.println("异步任务取消");break;}if (future.isDone()) {count = future.get();System.out.println(count);break;}}System.out.println("文章阅读业务执行完毕");return article + count;
}

6.常见失效场景

  1. 主启动类或者配置类没有添加@EnableAsync注解
  2. A方法调用被@Async注解修饰的B方法
@RestController
public class UserController {@Resourceprivate UserService userService;@RequestMapping("/getAll")public void getUsers(){System.out.println("业务开始");test();System.out.println("业务结束");}@Asyncpublic void test(){try {Thread.sleep(2000);System.out.println(Thread.currentThread().getName()+"查询到了所有的用户信息!");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
  1. 被@Async注解修饰的方法必须不可以是static和private,必须为public
  2. 需要通过@Autowired或@Resource进行注入,不可手动new,基于SpringAOP实现

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

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

相关文章

Windows版本Docker安装详细步骤

文章目录 下载地址安装异常处理docker desktop requires a newer wsl 下载地址 https://desktop.docker.com/win/stable/Docker%20Desktop%20Installer.exe 安装 双击下载的文件Docker Desktop Installer.exe进行安装 点击OK 开始安装 安装完成点击Close and restart&…

辉瑞乡村振兴战略下传统村落文化旅游设计小红书中美德少许

辉瑞乡村振兴战略下传统村落文化旅游设计小红书中美德少许

HodlSoftware-免费在线PDF工具箱 加解密PDF 集成隐私保护功能

HodlSoftware是什么 HodlSoftware是一款免费在线PDF工具箱&#xff0c;集合编辑 PDF 的简单功能&#xff0c;可以对PDF进行加解密、优化压缩PDF、PDF 合并、PDF旋转、PDF页面移除和分割PDF等操作&#xff0c;而且工具集成隐私保护功能&#xff0c;文件只在浏览器本地完成&…

【论文笔记】Planning and Decision-Making for Autonomous Vehicles

文章目录 Summary1. INTRODUCTION2. MOTION PLANNING AND CONTROL2.1. Vehicle Dynamics and Control2.2. Parallel Autonomy2.3. Motion Planning for Autonomous Vehicles 3. INTEGRATED PERCEPTION AND PLANNING3.1. From Classical Perception to Current Challenges in Ne…

知乎如何精准引流?

知乎&#xff0c;用过的人都知道&#xff0c;它是一个相当重要的引流平台。因为它用户规模大、粘性高、活跃性强、百度权重高&#xff0c;流量也相对精准&#xff0c;这也意味者变现能力强。 做引流的朋友都知道&#xff0c;想要把用户从别的平台引流到自己微信上&#xff0c;就…

代码随想录打卡—day46—【DP】— 8.29 背包END

1 139. 单词拆分 139. 单词拆分 做了很久...估计2h 一开始我的思路卡死了 看题解之后的思路的详解见注释&#xff0c; 我的写法和carl 答案在一些微小的细节上略有不同&#xff0c;我的更好理解&#xff0c;但他的解法更简单。 我写的过程中&#xff0c;需要注意下标和字符…

ffmpeg windows环境MinGW+msys2编译so库

一、安装MinGW 1.1、下载MinGW 1.2、下载完成后&#xff0c;会得到一个名为 mingw-get-setup.exe 的安装包&#xff0c;双击打开它&#xff0c;可以看到如下的对话框&#xff1a; 1.3、直接点击“Install”&#xff0c;进入下面的对话框 1.4、可根据自己操作系统的实际情况&am…

数字孪生:重塑政府决策与公共服务

在之前的文章中为大家分享了数字孪生在很多行业的应用场景&#xff0c;本文和大家一起探讨一下数字孪生在政务管理方面能有哪些应用&#xff0c;以及其对公共服务提供的积极影响。 1&#xff09;城市规划方面 数字孪生技术可用于模拟城市的发展和规划。政府可以建立城市的虚拟…

C++ DAY6

一、菱形继承 又叫钻石继承&#xff0c;由公共子类派生出多个中间子类&#xff0c;又由多个中间子类派生出汇聚子类&#xff0c;汇聚子类会 从中间子类得到从公共基类继承下来的多个成员。 A --------公共基类/ \B C ------- 中间子类\ /D -------…

聚类分析 | MATLAB实现基于DBSCAD密度聚类算法可视化

聚类分析 | MATLAB实现基于LP拉普拉斯映射的聚类可视化 目录 聚类分析 | MATLAB实现基于LP拉普拉斯映射的聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于DBSCAD密度聚类算法可视化&#xff0c;MATLAB程序。 使用带有KD树加速的dbscan_with_kdtree函数进行…

重排链表(C语言)

题目&#xff1a; 示例&#xff1a; 思路&#xff1a; 这题我们将使用栈解决这个问题&#xff0c;利用栈先进后出的特点&#xff0c;从链表的中间位置进行入栈&#xff0c;寻找链表的中间位置参考&#xff1a;删除链表的中间节点&#xff0c;之后从头开始进行连接。 本题使用…

Kali 软件管理

kali 更新 1. 查看发行版本 ┌──(root㉿kali)-[~] └─# lsb_release -a No LSB modules are available. Distributor ID: Kali Description: Kali GNU/Linux Rolling Release: 2023.2 Codename: kali-rolling2. 查看内核版本 ┌──(root㉿kali)-[~] └─…