异步任务
一、使用背景
在多数的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类
importlombok.extern.slf4j.Slf4j;importorg.springframework.scheduling.annotation.Async;importorg.springframework.stereotype.Service;/**
* 提供异步任务的服务类
*/@Service@Slf4jpublicclass executeService {/**
* 异步任务:休眠10秒后,输出"已执行"
*/@Async// 使用异步任务publicvoidexecute(){try{/* 假定有一个任务需要执行10秒 */Thread.sleep(10000);}catch(InterruptedException e){thrownewRuntimeException(e);}// 打印日志信息
log.info("任务已执行完成");}}
4.3 controller类
importcom.hui.service.executeService;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.annotation.Resource;@RestControllerpublicclassUserController{@Resourceprivate executeService wakeService;@GetMapping("/execute")publicStringisWakeUp(){// 执行任务
wakeService.execute();return"ok";}}
4.4 SpringBoot 启动类
importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.scheduling.annotation.EnableAsync;@EnableAsync// 启动异步任务注解@SpringBootApplicationpublicclassAsyncApplication{publicstaticvoidmain(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 方法的调用。
同时,异步方法不能在同一个类中被调用,否则注解会失效,并报错。
版权归原作者 野生派蒙 所有, 如有侵权,请联系我们删除。