首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >我就因为说了直接用@Async,面试官就让我回家等通知

我就因为说了直接用@Async,面试官就让我回家等通知

作者头像
一只牛博
发布2025-05-30 22:03:48
发布2025-05-30 22:03:48
6600
代码可运行
举报
运行总次数:0
代码可运行

这玩意是什么

@Async 是 Spring 提供的一种注解,用于简化异步方法的开发。它允许我们将特定的方法或类的所有方法标记为异步执行,以提高性能和响应速度,尤其是在执行非阻塞任务或耗时操作时非常有用。

启用异步支持

必须在 Spring 配置类中添加 @EnableAsync 注解以启用异步处理。

代码语言:javascript
代码运行次数:0
运行
复制
@Configuration
@EnableAsync
public class AsyncConfig {
}

直接用存在的问题

调用的流程
  • 注册代理:

Spring 在初始化时通过 AsyncAnnotationBeanPostProcessor 识别带有 @Async 注解的 bean,在这些 bean 上创建代理对象。

  • 方法拦截:

当代理对象的方法被调用时,Spring 的 AOP 拦截器会检测到 @Async 注解。

image-20241210135939626
image-20241210135939626

这玩意的意思就是你自己定义了线程池那就用你的,否则就用SimpleAsyncTaskExecutor

  • 其一是你在@Async注解中指定了线程池
  • 其二是你没在@Async中指定,但是你在别的地方定义了一个线程池(他也会找到),但是你如果定义了多个就会出现问题
SimpleAsyncTaskExecutor

这玩意存在大坑,因为当你不指定线程池的话,它会默认无线增加,不会复用线程,严格意义上来讲它并没有真正意义上实现线程池功能

image-20241210141515655
image-20241210141515655

场景测试

注意一定要先加上@EnableAsync注解

不配置线程池
异步方法
代码语言:javascript
代码运行次数:0
运行
复制
@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();
  }
}
测试调用
代码语言:javascript
代码运行次数:0
运行
复制
@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);
}
结果
image-20241210151737060
image-20241210151737060

上面的图中我们可以看出,线程出现了复用,而且线程名称也并非SimpleAsyncTaskExecutor,很显然不太对。除非Spring在启动的时候默认加了一个线程池,可以在启动的时候打印一下

代码语言:javascript
代码运行次数:0
运行
复制
@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()));
}
image-20241210152433118
image-20241210152433118
配置一个线程池
配置类
代码语言:javascript
代码运行次数:0
运行
复制
@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;
}
结果
image-20241210153039277
image-20241210153039277

结果与我们上面定义的现场名称也能对的上。

配置两个线程池

直接上结果

image-20241210153306424
image-20241210153306424

所以存在多个线程池的时候它会选择默认的,而这个也可以发现,他不会存在线程复用的情况

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 这玩意是什么
  • 直接用存在的问题
    • 调用的流程
      • SimpleAsyncTaskExecutor
  • 场景测试
    • 不配置线程池
      • 异步方法
      • 测试调用
      • 结果
    • 配置一个线程池
      • 配置类
    • 结果
  • 配置两个线程池
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档