@Async 异步方法,并配置定制线程池
@Async
是 Spring 框架提供的一个注解,用于异步执行方法。它的主要作用是将方法的执行放到一个独立的线程中,从而不会阻塞主线程,提高系统的并发性能和响应速度。
@Async
的作用
-
非阻塞执行
- 被
@Async
注解的方法会在一个独立的线程中执行,调用者无需等待方法执行完成,可以立即返回。
- 被
-
提高并发性能
- 适合处理耗时操作(如文件导出、数据上传、复杂计算等),避免阻塞主线程,提升系统的吞吐量。
-
简化异步编程
- 使用
@Async
可以避免手动创建和管理线程,Spring 会自动处理线程池和任务调度。
- 使用
使用场景
-
文件导出
- 用户发起导出请求后,系统立即返回响应,后台异步生成文件并上传。
-
发送通知
- 发送邮件、短信或站内信时,异步执行以避免阻塞主线程。
-
数据处理
- 对大量数据进行处理或计算时,异步执行以提高效率。
-
调用外部服务
- 调用第三方 API 或服务时,异步执行以避免阻塞主线程。
如何使用 @Async
1. 启用异步支持
在 Spring Boot 启动类或配置类上添加 @EnableAsync
注解:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 标记异步方法
在需要异步执行的方法上添加 @Async
注解:
@Service
public class MyService {
@Async
public void asyncMethod() {
// 耗时操作
System.out.println("异步方法执行中,线程:" + Thread.currentThread().getName());
}
}
3. 调用异步方法
从其他类中调用异步方法时,Spring 会自动将其放到独立线程中执行:
@RestController
public class MyController {
@Autowired
private MyService myService;
@GetMapping("/test")
public String testAsync() {
myService.asyncMethod();
return "异步方法已调用,请查看控制台日志。";
}
}
注意事项
-
返回值
- 如果异步方法需要返回值,可以使用
Future
或CompletableFuture
作为返回类型。
- 如果异步方法需要返回值,可以使用
-
线程池配置
- 默认情况下,Spring 使用简单的线程池执行异步任务。可以通过配置自定义线程池:
@Configuration public class AsyncConfig { @Bean(name = "taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(50); executor.setThreadNamePrefix("Async-"); executor.initialize(); return executor; } }
- 在
@Async
注解中指定线程池:@Async("taskExecutor") public void asyncMethod() { // 异步执行 }
- 默认情况下,Spring 使用简单的线程池执行异步任务。可以通过配置自定义线程池:
-
异常处理
- 异步方法中的异常不会传播到调用者,需要在方法内部处理或通过
AsyncUncaughtExceptionHandler
捕获。
- 异步方法中的异常不会传播到调用者,需要在方法内部处理或通过
-
同类调用失效
- 如果在一个类中直接调用
@Async
方法,异步不会生效。需要通过 Spring 代理调用(如从另一个类中调用)。
- 如果在一个类中直接调用
示例:异步导出文件
以下是一个完整的异步导出文件示例:
1. 启用异步支持
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 异步导出服务
@Service
public class ExportService {
@Async
public void exportDataAsync(String fileName, List<ExportData> dataList) {
try {
// 生成 Excel 文件
File file = new File(fileName);
EasyExcel.write(file, ExportData.class).sheet("Sheet1").doWrite(dataList);
// 模拟上传至 COS
System.out.println("文件已生成,开始上传...");
Thread.sleep(5000); // 模拟上传耗时
System.out.println("文件上传完成,下载链接:https://example.com/" + fileName);
// 删除本地临时文件
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. 控制器
@RestController
@RequestMapping("/export")
public class ExportController {
@Autowired
private ExportService exportService;
@PostMapping("/start")
public ResponseEntity<String> startExport() {
// 模拟数据
List<ExportData> dataList = new ArrayList<>();
dataList.add(new ExportData("1", "测试1", "2023-10-01"));
dataList.add(new ExportData("2", "测试2", "2023-10-02"));
// 异步导出
String fileName = "export_data_" + System.currentTimeMillis() + ".xlsx";
exportService.exportDataAsync(fileName, dataList);
// 立即返回响应
return ResponseEntity.ok("导出任务已开始,请稍后查看下载链接。");
}
}
总结
@Async
是 Spring 提供的强大工具,可以轻松实现异步编程,提升系统性能。通过合理使用 @Async
,可以避免阻塞主线程,提高用户体验。如果有其他问题,欢迎随时提问! 😊