Spring框架提供的@Async注解的异步方法使用注意事项

@Async 是 Spring 框架提供的用于异步执行方法的注解,使用时需要注意以下几个关键点,以确保正确实现异步功能并避免常见问题:

1.首先要在springBoot项目内创建线程池配置类:

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 线程池配置
 *
 * @author jsdye
 **/
@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
    }
}

有了这个线程池,就可以直接在异步方法上使用@Async注解(当 Spring 容器中只存在一个 TaskExecutor 或 ThreadPoolTaskExecutor 类型的 Bean(即你配置的 threadPoolTaskExecutor)时
Spring 会自动将它作为所有 @Async 方法的默认线程池(即使不显式指定名称),若存在多个TaskExecutor 或 ThreadPoolTaskExecutor 类型的 Bean,就需要显示指定用哪一个Bean,例如:

@Async("threadPoolTaskExecutor")
    public void saveOrEditBoxInfo(String deviceCode, String jsonString) {
        //业务代码

    }

);

;若没有这种线程池,那么使用单独@Async注解,就会很消耗性能(@Async注解默认使用 SimpleAsyncTaskExecutor异步执行器(每次调用新建线程,导致线程不可复用,不推荐生产环境使用)

2. 开启异步支持

在 Spring Boot 应用中,需要在主类或配置类上添加 @EnableAsync 注解:

@SpringBootApplication
@EnableAsync  // 启用异步方法支持
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3. 方法必须是 public 且非静态

@Async 只能用于 public 方法,且不能是 static 方法。因为 Spring 通过 AOP(面向切面编程)代理实现异步,而私有 / 静态方法无法被代理。

4. 避免方法内部调用

同一个类中的方法调用带 @Async 的方法会失效,因为 AOP 代理是通过外部调用触发的。例如:

public class MyService {
    public void doSomething() {
        // 错误:this 指向当前对象,而非代理对象
        this.asyncMethod(); 
    }

    @Async
    public void asyncMethod() {
        // 异步执行的代码
    }
}

解决方案:将异步方法提取到另一个 Bean 中;

或通过依赖注入获取当前 Bean 的代理对象例子如下:

@Service
public class MyService {

    @Autowired
    private MyService self;  // 注入当前Bean的代理对象

    @Async("threadPoolTaskExecutor")
    public CompletableFuture<String> asyncMethod() {
        System.out.println("执行线程: " + Thread.currentThread().getName());
        return CompletableFuture.completedFuture("异步结果");
    }

    public void syncMethod() {
        System.out.println("主线程: " + Thread.currentThread().getName());
        self.asyncMethod();  // ✅ 通过代理对象调用,异步生效
    }
}

5. 返回值类型限制

  • 无返回值:方法应声明为 void
  • 有返回值:必须返回 CompletableFutureFuture 或其子类,并通过 AsyncResult 包装结果:
@Async
public CompletableFuture<String> asyncWithResult() {
    // 异步处理
    return CompletableFuture.completedFuture("结果");
}

若返回值类型不匹配(如直接返回 String),会抛出异常。

6. 异常处理

  • 无返回值方法:异常会被 AsyncUncaughtExceptionHandler 捕获,需自定义处理器:
  • @Configuration
    public class AsyncConfig implements AsyncConfigurer {
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return new CustomAsyncExceptionHandler();
        }
    }
    

    有返回值方法:异常会被封装在 Future 中,需通过 future.get() 捕获。

7. 事务与异步的冲突

异步方法与事务管理(如 @Transactional)结合时需谨慎,因为两者使用不同的 AOP 代理机制。例如:

  • 异步方法中开启的事务可能无法正确传播。
  • 建议将事务操作放在同步方法中,异步方法仅处理非事务逻辑。

8. 序列化问题

若异步方法在分布式环境中跨进程调用(如通过消息队列),参数和返回值必须可序列化(实现 Serializable 接口)。

9. 测试异步方法

单元测试中,异步方法可能不会立即执行。可使用 @EnableAsync@Async 在测试类中模拟异步行为,或通过 CompletableFuture.get() 等待结果。

总结

合理使用 @Async 能显著提升应用性能,但需注意代理机制、线程池配置和异常处理等细节。建议结合自定义线程池和完善的监控机制,确保异步任务的稳定性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值