目录
1.说明
2.实现原理
3.示例
4.总结
1.说明
@Async
是 Spring 框架提供的一个注解,用于标记方法为异步执行。被标记的方法将在调用时立即返回,而实际的方法执行将在单独的线程中进行。
@Async
注解有一个可选属性:指定要使用的特定线程池的 bean 名称
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
/**
* 指定要使用的执行器(线程池)的限定符值
*/
String value() default "";
}
@Async
方法可以有以下返回类型:
-
void
:无返回值 -
Future
:返回 Future 对象,可用于获取异步执行结果 -
CompletableFuture
/ListenableFuture
:更现代的异步结果处理方式
2.实现原理
基于 Spring AOP(面向切面编程)和任务执行器(TaskExecutor)框架。
3.示例
①启动类中开启异步支持
@EnableAsync // 开启异步支持
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
EnableAsync有两个主要参数: mode及
proxyTargetClass
@EnableAsync
通过 mode
属性来配置代理方式:
AdviceMode
枚举有两种选择:
-
AdviceMode.PROXY
(默认值) - 使用标准 Spring AOP 代理-
对接口使用 JDK 动态代理
-
对类使用 CGLIB 代理
-
-
AdviceMode.ASPECTJ
- 使用 AspectJ 编织(weaving)-
需要额外的 AspectJ 依赖
-
不需要接口也能代理
-
可以代理更多方法类型(如 private 方法)
-
proxyTargetClass:指定使用
CGLIB 代理还是JDK动态代理
proxyTargetClass = true
表示:
-
强制使用 CGLIB 代理,即使目标类实现了接口
-
代理目标类本身,而不是其实现的接口
-
可以代理没有接口的类
默认行为(proxyTargetClass = false
或未指定)
-
如果目标类实现了接口 → 使用 JDK 动态代理
-
如果目标类没有实现接口 → 使用 CGLIB 代理
一般来说使用AdviceMode.PROXY及proxyTargetClass = true
②配置线程池
可以配置多个线程池
package com.example.demo1.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig {
@Bean("executorPool1")
public ThreadPoolTaskExecutor executorPool1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);// 核心线程数
executor.setMaxPoolSize(10);// 最大线程数
executor.setQueueCapacity(100);// 队列容量
executor.setKeepAliveSeconds(60);// 空闲线程的存活时间
executor.setThreadNamePrefix("demo1-pool-");// 线程名称前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 拒绝策略,让调用者线程自己执行被拒绝的任务
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //默认的拒绝策略,会抛出RejectedExecutionException异常
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 拒绝策略,直接丢弃任务,不抛出异常
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());// 拒绝策略,丢弃队列中最老的任务,尝试再次提交当前任务
executor.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成
executor.setAwaitTerminationSeconds(60); // 等待终止的最长时间(秒)
return executor;
}
@Bean("executorPool2")
public ThreadPoolTaskExecutor executorPool2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);// 核心线程数
executor.setMaxPoolSize(10);// 最大线程数
executor.setQueueCapacity(100);// 队列容量
executor.setKeepAliveSeconds(60);// 空闲线程的存活时间
executor.setThreadNamePrefix("demo1-pool-");// 线程名称前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 拒绝策略,让调用者线程自己执行被拒绝的任务
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); //默认的拒绝策略,会抛出RejectedExecutionException异常
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());// 拒绝策略,直接丢弃任务,不抛出异常
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());// 拒绝策略,丢弃队列中最老的任务,尝试再次提交当前任务
executor.setWaitForTasksToCompleteOnShutdown(true); // 关闭时等待任务完成
executor.setAwaitTerminationSeconds(60); // 等待终止的最长时间(秒)
return executor;
}
}
③定义异步方法
package com.example.demo1.logic;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
@Service
public class AsyncLogic {
@Async("executorPool1")
public CompletableFuture<String> process1(String item) {
CompletableFuture<String> future = new CompletableFuture<>();
try {
System.out.println("线程名称:" + Thread.currentThread().getName());
Thread.sleep(1000);
future.complete("Processed: " + item);
} catch (Exception e) {
e.printStackTrace();
future.completeExceptionally(e);
}
return future;
}
@Async("executorPool2")
public Future<String> process2(String item) {
try {
System.out.println("线程名称:" + Thread.currentThread().getName());
Thread.sleep(1000);
return AsyncResult.forValue("Processed: " + item);
} catch (Exception e) {
e.printStackTrace();
return AsyncResult.forExecutionException(e);
}
}
@Async("executorPool1")
public void process3(String item) {
try {
System.out.println("线程名称:" + Thread.currentThread().getName());
Thread.sleep(1000);
System.out.println("执行");
} catch (Exception e) {
e.printStackTrace();
}
}
}
④调用异步方法
package com.example.demo1;
import com.example.demo1.logic.AsyncLogic;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
@SpringBootTest
public class AsyncTest {
@Autowired
private AsyncLogic asyncLogic;
@Test
public void test114() {
System.out.println("调用异步方法前");
CompletableFuture<String> completableFuture = asyncLogic.process1("item");
Future<String> item = asyncLogic.process2("item");
asyncLogic.process3("item");
System.out.println("执行其他操作,不阻塞主线程");
try {
System.out.println("获取异步任务结果,阻塞主线程");
String result = completableFuture.get();
System.out.println("异步任务结果1:" + result);
String s = item.get();
System.out.println("异步任务结果2:" + s);
} catch (Exception e) {
System.out.println("捕捉到异常");
}
System.out.println("调用异步方法后");
}
}
4.总结
1. 必须通过 Spring Bean 调用
❌ 错误:直接调用 this.asyncMethod()(同一类内调用不生效)。
✅ 正确:通过 @Autowired 注入自身或使用其他 Bean 调用。
2. 异常处理
默认静默吞异常,建议添加异常处理器:
异常时记录日志,并发送钉钉通知
3. 方法可见性
@Async 需作用于 public 方法,私有方法无效。