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.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
4.2 编写service类
import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; /** * 提供异步任务的服务类 */ @Service @Slf4j public class executeService { /** * 异步任务:休眠10秒后,输出"已执行" */ @Async // 使用异步任务 public void execute() { try { /* 假定有一个任务需要执行10秒 */ 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; @RestController public 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 // 启动异步任务注解 @SpringBootApplication public 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 方法的调用。
同时,异步方法不能在同一个类中被调用,否则注解会失效,并报错。
到此这篇关于SpringBoot实现异步任务的项目实践的文章就介绍到这了,更多相关SpringBoot 异步任务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!