依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

限时开通VIP永久会员,可免费下载所有附件
查看: 42|回复: 0

Spring boot 中使用 @Async 注解时要避开的 7 大错误

[复制链接] 主动推送

1830

主题

1837

帖子

2791

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2791
发表于 2024-10-6 15:01:46 | 显示全部楼层 |阅读模式
Spring boot 中使用 @Async 注解时要避开的 7 大错误
在现代应用程序中,异步编程已成为提升性能和用户体验的关键手段之一。特别是在处理 I/O 密集型任务(如文件上传、数据库查询、远程服务调用等)时,异步执行能够防止主线程被阻塞,显著提高系统的响应能力。Spring Boot 提供的 @Async 注解极大地简化了异步任务的实现,通过它,开发者可以轻松地将同步方法转为异步方法执行。然而,尽管 @Async 的使用非常便捷,若使用不当,可能会带来一系列的潜在问题,如任务未正确执行、线程池饱和等。
为了帮助开发者更好地掌握 @Async 的正确用法,本文将深入探讨使用 @Async 注解时常见的七个错误,帮助避免这些问题。
@Async 注解简介
@Async 注解用于声明方法异步执行。它可以应用于方法上,使得该方法的执行在单独的线程中进行,而不会阻塞调用方线程。当我们在 Spring Boot 项目中使用 @Async 时,Spring 会自动为这些方法创建新的线程进行异步调用,调用者可以继续执行其他操作。
在异步任务中,有以下几点需要特别注意:
  • 线程池的管理:为了避免不必要的性能问题,异步任务的执行应当在合适配置的线程池中进行,默认情况下,Spring 会提供一个简单的线程池,然而这个默认线程池可能并不适用于高并发的应用场景。
  • 返回值管理:异步方法通常会返回 Future 或 CompletableFuture,以便调用方能够监控异步任务的完成状态或获取其执行结果。
  • 异常处理:异步任务中的异常不会被立即抛出给调用者,因此需要通过适当的方式捕获和处理这些异常,防止它们被忽略。

接下来我们将介绍在使用 @Async 时应避免的七个常见错误,并给出详细解释。
1. 忘记启用异步支持
错误描述:在使用 @Async 注解时,如果未在项目中显式启用异步支持,@Async 将不会生效,方法依然会在当前线程中执行。
深入解释:Spring Boot 需要通过 @EnableAsync 注解来启用异步功能。如果你忘记添加这个注解,@Async 注解不会真正让方法异步执行。虽然代码中可以正常编译和运行,但执行异步任务的方法实际上还是在调用线程中同步运行。这会导致你认为方法已经异步执行,然而在实际应用中,任务还是阻塞了主线程。
正确做法:确保在 Spring Boot 的主启动类或配置类上添加 @EnableAsync 注解来启用异步支持。
  1. @SpringBootApplication
  2. @EnableAsync
  3. public class AsyncApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(AsyncApplication.class, args);
  6.     }
  7. }
复制代码
2. 忽略线程池配置
错误描述:不为异步任务配置合适的线程池,使用 Spring 默认的线程池,这会在高并发下导致线程池饱和,影响系统性能。
深入解释:Spring 提供了一个简单的默认线程池 SimpleAsyncTaskExecutor,该线程池不进行任务排队,每次都会创建新的线程。对于小型应用,默认线程池可能足够,但在高并发场景下,过多的线程创建会导致资源耗尽。此外,线程池需要根据业务场景合理配置,如核心线程数、最大线程数、任务队列容量等。如果不对线程池进行自定义配置,应用程序可能会因线程池不当而导致性能瓶颈,甚至线程饥饿。
正确做法:通过 ThreadPoolTaskExecutor 来自定义线程池,并将其与 @Async 注解关联。合理设置线程池的大小、队列容量等参数,确保异步任务能够高效运行。
  1. import lombok.Data;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.scheduling.annotation.EnableAsync;
  6. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

  7. import java.util.concurrent.Executor;

  8. @Data
  9. @Configuration
  10. @EnableAsync
  11. @ConfigurationProperties(prefix = "async.threadpool")
  12. public class AsyncConfig {

  13.     private int corePoolSize;
  14.     private int maxPoolSize;
  15.     private int queueCapacity;

  16.     @Bean(name = "taskExecutor")
  17.     public Executor taskExecutor() {
  18.         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  19.         executor.setCorePoolSize(corePoolSize);
  20.         executor.setMaxPoolSize(maxPoolSize);
  21.         executor.setQueueCapacity(queueCapacity);
  22.         executor.setThreadNamePrefix("AsyncThread-");
  23.         executor.initialize();
  24.         return executor;
  25.     }
  26. }
复制代码
3. 同步方法内调用异步方法
错误描述:在同一个类中的同步方法调用异步方法时,异步方法不会真正异步执行。
深入解释:Spring AOP(面向切面编程)机制通过代理对象的方式来管理 @Async 方法。然而,如果在同一个类内调用 @Async 注解的方法时,由于 Spring 无法通过代理对象对其进行管理,导致异步方法会以同步方式执行。这样,即便你为方法添加了 @Async 注解,也不会发挥异步执行的作用。
正确做法:确保异步方法由外部类调用,这样 Spring 的代理机制才能生效。
  1. @Service
  2. public class SyncService {

  3.     private final AsyncService asyncService;

  4.     public SyncService(AsyncService asyncService) {
  5.         this.asyncService = asyncService;
  6.     }

  7.     public void callAsyncMethod() {
  8.         asyncService.asyncMethod();  // 通过外部类调用异步方法
  9.     }
  10. }
复制代码
4. 异步方法返回 void 而非 Future
错误描述:异步方法直接返回 void,而不是 Future 或 CompletableFuture。
深入解释:虽然异步方法可以返回 void,但是这会使调用者无法跟踪异步任务的状态。无法得知任务何时完成或是否出错。返回 Future 或 CompletableFuture 可以让调用方根据需要获取异步任务的结果、处理异常或等待任务完成。特别是在需要处理任务完成状态或异常的场景中,使用 CompletableFuture 更为合适。
正确做法:异步方法应尽量返回 CompletableFuture,以便调用者能够获取异步任务的结果或处理其完成状态。
  1. @Async
  2. public CompletableFuture<String> asyncWithResult() {
  3.     return CompletableFuture.completedFuture("任务完成");
  4. }
复制代码
5. 忽略异步任务中的异常处理
错误描述:没有处理异步方法中的异常,导致异常被忽略或无法正常反馈。
深入解释:异步方法执行时,异常不会自动抛给调用者,因此如果异步任务中发生了异常,它们可能会被忽略。忽略异常会使得程序运行状态难以预测,甚至可能造成数据不一致、服务中断等严重问题。通过 CompletableFuture 提供的 exceptionally 方法,或手动捕获异常,可以确保任务中的异常能够得到处理。
正确做法:在异步任务中处理异常,确保异常信息能够被记录或反馈。
  1. @Async
  2. public CompletableFuture<String> asyncWithErrorHandling() {
  3.     try {
  4.         // 模拟可能抛出异常的代码
  5.         int result = 10 / 0;
  6.         return CompletableFuture.completedFuture("结果:" + result);
  7.     } catch (Exception e) {
  8.         return CompletableFuture.completedFuture("任务失败,异常:" + e.getMessage());
  9.     }
  10. }
复制代码
6. 将 @Async 注解用于非 public 方法
错误描述:将 @Async 注解用于非 public 方法,导致方法不能异步执行。
深入解释:@Async 注解只能应用于 public 方法上,这是因为 Spring AOP 仅代理 public方法。如果你将 @Async 注解应用于 private 或 protected 方法,Spring 将无法为该方法生成代理对象,导致异步功能无法生效。
正确做法:确保异步方法是 public 访问级别。
  1. @Async
  2. public void correctAsyncMethod() {
  3.     // 正确的异步方法
  4. }
复制代码
7. 调用方未等待异步任务结果
错误描述:调用方未等待异步任务完成,导致异步任务结果无法使用。
深入解释:在某些场景下,调用方需要获取异步任务的结果,然而异步方法默认情况下是不会阻塞调用方的。如果调用方不等待结果,可能会导致任务尚未完成就继续处理后续逻辑,进而引发潜在问题。可以通过 CompletableFuture 的 join() 或 get() 方法等待异步任务完成,确保结果在后续逻辑中可用。
正确做法:在需要的情况下,通过 join() 方法等待异步任务完成。
  1. public String executeAsyncTask() {
  2.     CompletableFuture<String> future = futureService.asyncWithResult();
  3.     return future.join();  // 阻塞直到任务完成
  4. }
复制代码
总结
在现代应用中,异步编程是优化系统性能的关键手段之一,尤其是在处理大量 I/O 密集型任务时。Spring Boot 提供的 @Async 注解能够让开发者轻松实现异步任务,但使用不当可能带来严重的性能或逻辑问题。本文深入探讨了在使用 @Async 时常见的七个错误,从启用异步支持、线程池配置到异常处理和任务结果管理,逐一分析了错误产生的原因并提供了相应的解决方案。通过避免这些常见错误,大家可以确保异步任务能够在系统中高效、正确地执行。

相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-10-20 05:28

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表