说一说Springboot中使用异步@Async注解的一些流程以及注意事项。

1.在主应用类上添加@EnableAsync注解,启用异步支持


@SpringBootApplication
@EnableAsync
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

2.创建一个单独的异步执行类

@Service
public class AsyncService {

    @Async
    public void asyncMethod() {
        // 异步方法的代码
    }
}

3.在其他类的方法中调用它

@RestController
public class MyController {
    @Autowired
    private AsyncService asyncService;

    @GetMapping("/test")
    public String test() {
        // 执行异步任务
        asyncService.asyncMethod();
        return "ok";
    }
}

  • ==不要在同一个类中直接调用被@Async注解的方法,因为这会导致方法同步执行。==
  • 当一个异步方法B调用另一个异步方法A时,如果A也是异步的,则B的执行不会等待A完成。
  • 在异步方法中,事务会被异步地传播,这意味着如果父事务回滚,子事务(即异步方法)可能不会回滚。

==还要注意:==
当使用@Async注解时,默认情况下会使用一个简单的SimpleAsyncTaskExecutor来执行异步方法。但是,SimpleAsyncTaskExecutor并不是真正的线程池,它每次执行都会创建一个新的线程,这可能会导致系统资源耗尽,单机情况可以采用默认,但高并发情况推荐自定义创建一个线程池,例如创建一个“taskExecutor”名字的线程池。

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // 核心线程数,最小存活
        executor.setMaxPoolSize(10); // 允许最大线程数
        executor.setQueueCapacity(25); // 队列容量
        executor.setThreadNamePrefix("Async-"); // 线程名前缀
        executor.initialize();
        return executor;
    }
}

@Service
public class AsyncService {

    @Async("taskExecutor")
    public void asyncMethod() {
         // 这里将会使用注入的taskExecutor线程池执行异步方法
    }
}

只需要在@Async中指定线程池名称即可,
当然,也可以全局配置,比如在启动类@EnableAsync注解中指定默认的线程池Bean名称

@SpringBootApplication
@EnableAsync("taskExecutor")
public class MyApp {}

//后续 @Async可省略bean名称
 @Async
public void asyncMethod() {}


异步方法返回类型问题:
如果异步方法的返回类型不是void,调用者得到的将是代表异步操作的Future,而不是操作的实际结果。

@Async
public Future<String> asyncMethod() {}

目录