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 异步结果获取,代码更简洁。
相关推荐
SL_staff35 分钟前
物模型三要素误用避坑指南:属性、事件、服务的正确建模逻辑
java
一条泥憨鱼40 分钟前
【Redis | 黑马点评】短信登录功能 源码深度分析
java·redis·后端·session·黑马点评
威哥爱编程1 小时前
【AI全栈12-12】Spring Boot 3.x → 4.x 迁移实操:Jakarta 11、Jackson 3 与 AI 2.0
java·spring boot·后端
威哥爱编程1 小时前
【AI全栈12-11】Spring Boot 把 AI 接口真正上线扛量:限流 / 降级 / 可观测
java·spring boot·后端
小蒜学长1 小时前
基于SpringBoot+uni-app的闪洁家政系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·uni-app·家政服务
敲代码的彭于晏1 小时前
2026 K8s 零基础入门:手把手教你一步步搭建 Kubernetes 集群
java·运维·全栈
希洛兔1 小时前
状态模式详解:让对象随内部状态自动改变行为
java·设计模式·状态模式
需要8261 小时前
Spring Boot 启动流程:run() 里到底发生了什么
java·spring boot·后端
云絮.1 小时前
Mybatis(一)
java·数据库·mybatis
希洛兔2 小时前
里氏替换原则详解:子类必须能透明替换基类(含继承风险演示 + 正确重构 + JDK 案例)
java·里氏替换原则