SpringBoot 实现异步任务
异步任务
一、使用背景
在多数的Java项目中,在很多的场景都是用同步的方式去实现模块间的相互调用,在模块调用间可能会造成一些延迟,本篇文章将使用SpringBoot 去实现异步之间的调用,提高系统的并发性能、用户体验。
二、同步任务的优缺点
2.1 优点
-
简单直观:同步任务的执行是顺序的,代码执行的流程清晰明了,易于理解和调试。
-
避免并发问题:同步任务在单线程中执行,不会引发线程安全和数据一致性等并发问题。每次只有一个任务在执行,避免了竞态条件和资源竞争。
-
较少的资源消耗:同步任务不需要额外的线程资源来执行,只使用主线程。这样可以减少线程上下文切换的开销,降低系统的资源消耗。
-
异常处理简单:同步任务中的异常可以直接抛出,易于捕获和处理。可以在代码中使用try-catch语句来捕获异常,进行相应的异常处理逻辑
2.2 缺点
-
阻塞主线程:同步任务需要等待任务执行完成后才能继续执行下一个任务,阻塞主线程。如果一个任务执行时间过长,会导致整个系统的响应变慢,影响用户体验。
-
降低并发性能:由于同步任务需要按顺序执行,无法同时处理多个请求,降低了系统的并发性能和吞吐量。在高并发场景下,可能会导致系统处理能力不足。
-
响应时间不稳定:同步任务需要等待任务完成才返回结果,如果任务执行时间不可预知或变化较大,会导致响应时间不稳定,难以控制和优化。
-
潜在的死锁风险:当同步任务中存在资源竞争或循环依赖时,可能会导致死锁的产生。一旦发生死锁,程序无法进行进一步的执行,造成系统无法正常工作
2.3 总结
综上所述,同步任务简单直观,避免了并发问题和资源浪费,异常处理方便。但同时会阻塞主线程,降低并发性能,响应时间不稳定,并且潜在的死锁风险
三、异步任务的优缺点
3.1 优点
-
提高系统的并发能力:异步方式将耗时操作从主线程中分离出来,在后台线程中执行,不会阻塞主线程。这样可以同时处理多个请求,提高系统的并发能力和吞吐量。
-
提升系统的响应速度:由于异步方式不需要等待耗时操作的完成,主线程可以立即响应其他请求。这样可以减少用户等待时间,提升系统的响应速度,改善用户体验。
-
优化资源利用:异步方式可以在后台线程中执行耗时操作,释放主线程的资源,减少资源浪费。同时,可以根据需求合理调整线程池的大小,灵活配置线程资源,以提高系统的资源利用效率。
-
简化编程模型:异步方式可以使用简单的注解(如@Async)或异步框架,简化编程模型。开发者不需要手动处理线程的创建、管理和同步等细节,减少开发复杂性
3.2 缺点
-
需要额外的线程资源:异步方式需要创建额外的线程来执行耗时操作,增加了系统对线程资源的需求。如果线程资源不合理配置或管理不当,可能会导致性能下降、内存溢出等问题。
-
可能引入复杂性:异步方式可能引入了代码的复杂性。当异步操作涉及到多个线程之间的协调和通信时,可能需要更复杂的代码逻辑和同步机制,增加了代码维护的难度。
-
难以处理异常:异步操作的异常处理相对复杂,需要额外的关注和处理。异步方法的异常无法直接抛出到调用方,需要通过回调、Future对象或异步异常处理机制来进行处理。
-
可能的竞态条件和并发问题:在多线程环境下,异步方式可能出现竞态条件、资源竞争等并发问题,如线程安全性、数据一致性等。开发者需要进行合理的线程同步和数据保护,以避免潜在的问题
3.3 总结
异步方式可以提高系统的并发性能、响应速度和资源利用效率,简化编程模型。然而,需要注意线程资源的合理配置和管理,处理异常和并发问题,以保证异步方式的稳定和可靠性
四、Spring Boot 实现异步任务
4.0 项目结构
4.1 pom.xml
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starterartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-webartifactId>dependency><dependency><groupId>org.projectlombokgroupId><artifactId>lombokartifactId>dependency><dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-testartifactId><scope>testscope>dependency>
4.2 编写service类
import lombok.extern.slf4j.Slf4j;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Service@Slf4jpublic class executeService { @Async // 使用异步任务 public void execute() { try { Thread.sleep(10000); } catch (InterruptedException e) { throw new RuntimeException(e); } // 打印日志信息 log.info("任务已执行完成"); }}
4.3 controller类
import com.hui.service.executeService;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestControllerpublic class UserController { @Resource private executeService wakeService; @GetMapping("/execute") public String isWakeUp() { // 执行任务 wakeService.execute(); return "ok"; }}
4.4 SpringBoot 启动类
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync // 启动异步任务注解@SpringBootApplicationpublic class AsyncApplication {public static void main(String[] args) {SpringApplication.run(AsyncApplication.class, args);}}
4.5 测试
访问:http://localhost:8080/execute,当带上@Async 注解后,controller类会直接响应"ok",而不用去等待10秒,再去响应
10秒过后控制台会输出:“任务已执行完成”
五、使用异步任务注意点
5.1 启用异步支持
启用异步支持:确保在配置类或主启动类上添加 @EnableAsync 注解,以激活 Spring 的异步处理功能
5.2 异步方法边界
异步方法边界:@Async 注解只能应用在 public 方法上,因为 Spring 使用基于代理的机制,无法拦截非 public 方法的调用。
同时,异步方法不能在同一个类中被调用,否则注解会失效,并报错。
来源地址:https://blog.csdn.net/m0_62854966/article/details/131949295
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341