@Async 是 Spring 提供的一种注解,用于简化异步方法的开发。它允许我们将特定的方法或类的所有方法标记为异步执行,以提高性能和响应速度,尤其是在执行非阻塞任务或耗时操作时非常有用。
启用异步支持:
必须在 Spring 配置类中添加 @EnableAsync 注解以启用异步处理。
@Configuration
@EnableAsync
public class AsyncConfig {
}
Spring 在初始化时通过 AsyncAnnotationBeanPostProcessor 识别带有 @Async 注解的 bean,在这些 bean 上创建代理对象。
当代理对象的方法被调用时,Spring 的 AOP 拦截器会检测到 @Async 注解。
这玩意的意思就是你自己定义了线程池那就用你的,否则就用
SimpleAsyncTaskExecutor
这玩意存在大坑,因为当你不指定线程池的话,它会默认无线增加,不会复用线程,严格意义上来讲它并没有真正意义上实现线程池功能
注意一定要先加上
@EnableAsync
注解
@Async()
public void executeTask(int taskId) {
System.out.println(Thread.currentThread().getName() + " is executing task: " + taskId);
try {
// 模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@Test
public void parameterFreeAsync() throws InterruptedException {
// 提交 10 个任务
for (int i = 0; i < 10; i++) {
myAsyncService.executeTask(i);
}
// 主线程等待所有任务完成
Thread.sleep(15000);
// 再提交一些任务,观察线程是否复用
for (int i = 10; i < 15; i++) {
myAsyncService.executeTask(i);
}
Thread.sleep(10000);
}
上面的图中我们可以看出,线程出现了复用,而且线程名称也并非
SimpleAsyncTaskExecutor
,很显然不太对。除非Spring在启动的时候默认加了一个线程池,可以在启动的时候打印一下
@PostConstruct
public void checkExecutors() {
Map<String, Executor> executors = context.getBeansOfType(Executor.class);
System.out.println("Found Executors: " + executors.size());
executors.forEach((name, executor) ->
System.out.println("Executor Bean Name: " + name + ", Type: " + executor.getClass().getName()));
}
@Bean(name = "customTaskExecutor")
public Executor customTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(4);
// 最大线程数
executor.setMaxPoolSize(8);
// 队列容量
executor.setQueueCapacity(20);
// 空闲线程存活时间
executor.setKeepAliveSeconds(10);
executor.setThreadNamePrefix("ReusableThread-");
executor.initialize();
return executor;
}
结果与我们上面定义的现场名称也能对的上。
直接上结果
所以存在多个线程池的时候它会选择默认的,而这个也可以发现,他不会存在线程复用的情况