@Async的用法

转载请注明出处 http://www.paraller.com 原文排版地址 点击获取更好阅读体验

属性Bean: ``` @Configuration public class ContactsExecutor {

@Value("${contacts.thread.core-pool}")
private int corePoolSize;

@Value("${contacts.thread.max-pool}")
private int maxPoolSize;

@Value("${contacts.queue.capacity}")
private int queueCapacity;

@Value("${contacts.thread.timeout}")
private int threadTimeout;

@Bean
@Qualifier("contactsExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
    threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
    threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
    threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
    threadPoolTaskExecutor.setKeepAliveSeconds(threadTimeout);

    return threadPoolTaskExecutor;
}

} ```

线程配置文件:

```

thread pool and queue size for processing contacts data

contacts.thread.timeout=2 contacts.thread.core-pool=10 contacts.thread.max-pool=25 contacts.queue.capacity=25

```

主程序入口添加注释: ``` @EnableAsync @ComponentScan @EnableAutoConfiguration public class Application { ....... }

```

调用类: @Async("mainExecutor") public void methodA(){}

Configure queue and thread pool for async execution

<think> 我们正在讨论的是Spring框架中的@Async注解的使用方法和注意事项。根据用户的问题和提供的引用内容,我们需要总结@Async用法及其注意事项。 ### 回答结构: 1. **@Async的基本用法**:介绍如何启用异步功能以及如何标注方法。 2. **注意事项**:详细列出使用@Async时需要注意的各个点,并解释原因。 3. **示例代码**:给出正确使用@Async的示例。 4. **相关问题**:生成几个与@Async相关的问题。 ### 具体内容: #### 1. @Async的基本用法 - **启用异步**:在配置类上添加`@EnableAsync`注解,这样Spring就会扫描`@Async`注解的方法。 - **标注方法**:在需要异步执行的方法上添加`@Async`注解。该方法将在单独的线程中执行,从而不会阻塞调用线程。 示例配置: ```java @Configuration @EnableAsync public class AsyncConfig { // 可以自定义线程池,否则使用默认的 } ``` 异步方法: ```java @Service public class MyService { @Async public void asyncMethod() { // 异步执行的代码 } } ``` #### 2. @Async的注意事项 根据引用内容,我们总结如下: **注意事项:** 1. **不能使用static修饰异步方法**:因为静态方法不会由Spring代理,所以异步失效[^2]。 2. **异步方法和调用方法不能在同一个类中**:这是因为同一个类中的方法调用不会经过代理对象,因此异步方法会被同步执行[^2][^3]。 - 解决方法:将异步方法放在另一个Service中,通过注入的Service来调用。 3. **异步方法必须是public的**:因为Spring AOP只能代理public方法[^2]。 4. **确保异步类被Spring扫描到**:异步方法所在的类必须由Spring管理(如使用`@Component`、`@Service`等注解),并且确保已经启用异步(`@EnableAsync`)[^2]。 5. **不能手动new对象调用异步方法**:必须通过Spring容器注入的Bean来调用异步方法,否则代理失效[^2]。 6. **异常处理**: - 无返回值的异步方法:异常会被`AsyncUncaughtExceptionHandler`处理,但默认只记录错误日志。如果需要自定义处理,可以实现`AsyncUncaughtExceptionHandler`接口[^4]。 - 有返回值的异步方法(返回`Future`或`CompletableFuture`):需要在方法内部捕获异常并处理,或者在调用方通过`Future.get()`方法捕获异常[^4]。 示例:异常处理 ```java @Async public void asyncMethodWithException() { throw new RuntimeException("异步方法异常"); } // 自定义异常处理器 @Configuration public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { // 自定义处理逻辑 } } ``` 7. **线程池配置**:默认情况下,Spring使用简单的线程池。建议自定义线程池以控制并发行为(如核心线程数、队列容量、拒绝策略等)[^1]。 #### 3. 正确使用示例 ```java @Service public class TaskService { @Autowired private AsyncService asyncService; // 将异步方法放在另一个Service中 public void callAsync() { asyncService.asyncMethod(); // 异步执行 } } @Service public class AsyncService { @Async public void asyncMethod() { // 异步执行的任务 } } ``` #### 4. 相关问题 根据以上内容,生成相关问题: 1. 如何自定义@Async使用的线程池? 2. 如何捕获@Async异步方法中抛出的异常? 3. 在分布式系统中,@Async注解的方法能否保证任务不丢失? 4. 如何监控异步方法的执行情况(如耗时、成功率)? ### 回答: ### Spring @Async 使用详解 #### 一、基本使用流程 1. **启用异步支持** 在配置类添加`@EnableAsync`: ```java @SpringBootApplication @EnableAsync // 启用异步功能[^1] public class Application { ... } ``` 2. **标注异步方法** 在方法上添加`@Async`注解: ```java @Service public class EmailService { @Async // 标注为异步方法 public void sendMail(String content) { // 模拟邮件发送(耗时操作) System.out.println("异步发送邮件: " + content); } } ``` #### 二、六大核心注意事项 1. **禁止使用static修饰异步方法** ```java // 错误示例 ❌ @Async public static void asyncStaticMethod() { ... } ``` 原因:静态方法会导致Spring AOP代理失效[^2] 2. **避免同类内部调用** ```java @Service public class OrderService { public void createOrder() { this.processPayment(); // 同步调用 ❌ } @Async public void processPayment() { ... } } ``` 解决方案:通过代理对象调用(推荐拆分到不同服务类)[^2][^3] 3. **方法必须为public** ```java // 错误示例 ❌ @Async private void internalTask() { ... } ``` 原因:Spring AOP只能代理public方法[^2] 4. **确保Spring扫描到异步类** ```java // 正确示例 ✔️ @Service // 必须被Spring管理 public class AsyncTask { ... } ``` 5. **禁止手动new对象调用** ```java // 错误用法 ❌ new PaymentService().asyncProcess(); ``` 正确方式:通过依赖注入调用[^2] 6. **异常处理机制** - **无返回值方法**:实现`AsyncUncaughtExceptionHandler`接口 ```java @Configuration public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { // 发送告警邮件[^4] AlarmService.notify(ex.getMessage()); } } ``` - **有返回值方法**(返回`Future`/`CompletableFuture`): ```java @Async public Future<String> asyncWithResult() { try { // ... } catch (Exception e) { return new AsyncResult<>("error"); } } ``` #### 三、线程池自定义配置 默认线程池可能导致资源耗尽,建议自定义: ```java @Configuration @EnableAsync public class ThreadConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(100); executor.setThreadNamePrefix("Async-"); executor.initialize(); return executor; } } ``` > 配置要点:根据任务类型设置合理的队列容量和拒绝策略 #### 四、生产环境最佳实践 1. **超时控制** ```java @Async @Timeout(value = 30, unit = TimeUnit.SECONDS) // Spring 6.0+ public void longRunningTask() { ... } ``` 2. **事务边界分离** ```mermaid graph LR A[主线程] -->|提交事务| B[数据库] C[异步线程] -->|独立事务| D[写操作] ``` 注意:异步方法内数据库操作与主线程不在同一事务 3. **链路追踪集成** 在异步线程中传递TraceID: ```java @Async public void asyncWithTrace() { MDC.put("traceId", RequestContext.getTraceId()); // ... } ``` --- §§相关问题§§ 1. 如何自定义@Async使用的线程池? 2. 如何捕获@Async异步方法中抛出的异常? 3. 在分布式系统中,@Async注解的方法能否保证任务不丢失? 4. 如何监控异步方法的执行情况(如耗时、成功率)? </think> ### Spring @Async 使用指南及核心注意事项 #### 一、基本使用流程 1. **启用异步支持** 在配置类添加`@EnableAsync`: ```java @SpringBootApplication @EnableAsync // 启用异步功能[^1] public class Application { ... } ``` 2. **标注异步方法** 在方法上添加`@Async`注解: ```java @Service public class EmailService { @Async // 标注为异步方法 public void sendMail(String content) { // 模拟邮件发送(耗时操作) System.out.println("异步发送邮件: " + content); } } ``` #### 二、六大核心注意事项 1. **禁止使用static修饰异步方法** ```java // 错误示例 ❌ @Async public static void asyncStaticMethod() { ... } ``` 原因:静态方法会导致Spring AOP代理失效[^2] 2. **避免同类内部调用** ```java @Service public class OrderService { public void createOrder() { this.processPayment(); // 同步调用 ❌ } @Async public void processPayment() { ... } } ``` 解决方案:通过代理对象调用(推荐拆分到不同服务类)[^2][^3] ```java @Autowired private OrderService orderServiceProxy; // 注入代理对象 public void createOrder() { orderServiceProxy.processPayment(); // 异步调用 ✔️ } ``` 3. **方法必须为public** ```java // 错误示例 ❌ @Async private void internalTask() { ... } ``` 原因:Spring AOP只能代理public方法[^2] 4. **确保Spring扫描到异步类** ```java // 正确示例 ✔️ @Service // 必须被Spring管理 public class AsyncTask { ... } ``` 5. **禁止手动new对象调用** ```java // 错误用法 ❌ new PaymentService().asyncProcess(); ``` 正确方式:通过依赖注入调用[^2] ```java @Autowired private PaymentService paymentService; paymentService.asyncProcess(); // 异步执行 ✔️ ``` 6. **异常处理机制** - **无返回值方法**:实现`AsyncUncaughtExceptionHandler`接口 ```java @Configuration public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { @Override public void handleUncaughtException(Throwable ex, Method method, Object... params) { // 发送告警邮件[^4] AlarmService.notify(ex.getMessage()); } } ``` - **有返回值方法**(返回`Future`/`CompletableFuture`): ```java @Async public Future<String> asyncWithResult() { try { // ... } catch (Exception e) { return new AsyncResult<>("error"); } } ``` #### 三、线程池自定义配置 默认线程池可能导致资源耗尽,建议自定义: ```java @Configuration @EnableAsync public class ThreadConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(50); executor.setQueueCapacity(100); executor.setThreadNamePrefix("Async-"); executor.initialize(); return executor; } } ``` > 配置要点:根据任务类型设置合理的队列容量和拒绝策略 #### 四、生产环境最佳实践 1. **超时控制** ```java @Async @Timeout(value = 30, unit = TimeUnit.SECONDS) // Spring 6.0+ public void longRunningTask() { ... } ``` 2. **事务边界分离** ```mermaid graph LR A[主线程] -->|提交事务| B[数据库] C[异步线程] -->|独立事务| D[写操作] ``` 注意:异步方法内数据库操作与主线程不在同一事务 3. **链路追踪集成** 在异步线程中传递TraceID: ```java @Async public void asyncWithTrace() { MDC.put("traceId", RequestContext.getTraceId()); // ... } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值