JUC相关的函数、注解、变量杂记

1. @Async的作用

一、核心作用

@Async 是 Spring 提供的异步执行注解,作用:

  1. 把被标注的方法放到独立线程异步执行,不会阻塞当前调用主线程;
  2. 实现任务解耦、提升接口响应速度,常用于异步通知、日志、文件导出、消息发送等耗时操作。

二、使用前提(必须两步,缺一不可)

  1. 启动类添加 @EnableAsync 开启异步功能

java

复制代码
@SpringBootApplication
@EnableAsync // 开启Spring异步支持
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
  1. @Async 写在public 方法上,且调用方和异步方法不在同一个类(内部调用不生效,AOP 无法拦截)

三、两种返回形式

1. 无返回值(void)

适合不需要接收结果的耗时任务:发短信、记录操作日志

java

复制代码
@Async
public void sendSms(String phone) {
    // 耗时网络操作,异步执行,不阻塞主线程
}

2. 有返回值(返回 Future<T> / CompletableFuture<T>)

需要获取异步执行结果、做结果聚合

java

复制代码
@Async
public Future<Integer> countOrder() {
    int total = orderMapper.selectCount(null);
    return CompletableFuture.completedFuture(total);
}

// 调用
Future<Integer> future = orderService.countOrder();
Integer total = future.get(); // 阻塞等待异步结果

四、底层原理

Spring 通过 AOP 动态代理 拦截 @Async 方法:

  1. 拦截到方法后,把任务交给内置线程池 SimpleAsyncTaskExecutor;
  2. 新开子线程执行目标方法,主线程直接返回,不等待方法执行完毕。

五、默认线程池问题(重要)

默认使用 SimpleAsyncTaskExecutor:每次调用新建一个线程,无复用、无限创建线程,高并发会 OOM。

生产环境自定义线程池方案

java

复制代码
@Configuration
public class AsyncConfig {
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);    // 核心线程
        executor.setMaxPoolSize(50);     // 最大线程
        executor.setQueueCapacity(200);  // 队列
        executor.setThreadNamePrefix("async-task-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

// 指定使用自定义线程池
@Async("taskExecutor")
public void asyncTask(){}

六、常见坑

  1. 同类内部调用失效

java

复制代码
// 同一个类里调用,AOP代理拦截不到,同步执行
public void test(){
    asyncMethod(); // 无效,同步
}
@Async
public void asyncMethod(){}

解决:把异步方法抽离到单独 Service,或者通过 ApplicationContext 获取代理对象调用。

  1. 事务失效异步方法会新开线程,子线程和主线程是独立事务,主线程回滚不影响异步方法。

  2. 异常捕获void 异步方法抛出异常主线程感知不到,需要自定义 AsyncUncaughtExceptionHandler 统一捕获异常告警。

  3. 事务传播问题主线程事务不会传递到异步子线程,各自独立。

七、适用场景 & 不适用场景

适用

  • 异步通知:短信、邮件、站内信
  • 后置统计:操作日志、埋点数据上报
  • 耗时计算:报表生成、大数据导出
  • MQ 消息异步发送

不适用

  • 需要同步事务保证一致性的核心业务(订单创建 + 库存扣减不能分开异步)
  • 需要实时拿到返回结果且不能阻塞的简单接口(同步即可)

八、和手动创建线程的区别

  1. @Async 托管线程池,统一管控、可配置拒绝策略;
  2. 统一异常处理、线程复用,不用手动管理 Thread;
  3. 支持返回 Future 异步结果获取,代码更简洁。
相关推荐
天河归来8 小时前
第三方接口不稳定,如何让核心任务继续完成
java·大数据
Knight_AL9 小时前
Java 文件下载时文件名中的 `#` 被转换成 `%23`?一次 URL 编码与解码问题排查
java·开发语言
利威尔xu9 小时前
Go IM 源码实战(14):本地缓存快 3000 倍,失效却难 10 倍
后端·缓存·微服务·面试·golang
砚底藏山河10 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
利威尔xu10 小时前
Go IM 源码实战(13):30 个会话只有 2 个红点,未读数错在三条路径
redis·后端·微服务·面试·golang
猿究院_夏燊11 小时前
MySQL 的四种隔离级别
java·数据库·mysql
码流子11 小时前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
霸道流氓气质12 小时前
AI 流式对话与实时聊天平台:SSE 解码竞态、有状态会话隔离与背压取消的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
云创智城-yuncitys12 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
文丑颜不良啊12 小时前
LeetCode1661~1680题目解析
java·leetcode