Spring异步机制:@Async
概述
当一个方法标注@Async注解时,该方法的调用将异步发生;这意味着调用者将在调用后立即返回,方法的实际执行将发生在提交给Spring TaskExecutor的任务中。
示例
示例1
使用@EnableAsync注解启用异步机制
@EnableAsync @Configuration public class AsyncConfig { }
@Service public class AsyncJob { @Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously: start." + Thread.currentThread().getName()); try { Thread.sleep(10 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Execute method asynchronously: end." + Thread.currentThread().getName()); } }
@RestController @RequestMapping("/home") public class HomeController { @Autowired private AsyncJob asyncJob; @GetMapping("/user-info") public String queryUserName() { asyncJob.asyncMethodWithVoidReturnType(); return "test - user"; } }
运行结果
Postman
日志
从上述日志中线程的名称可以知道,本示例中异步执行方法所用的线程池为Spring boot默认配置的线程池(TaskExecutionAutoConfiguration)
示例2
自定义线程池
@Configuration public class ThreadPoolConfig { @Bean public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor(); // 核心线程数 poolExecutor.setCorePoolSize(1); // 最大线程数 poolExecutor.setMaxPoolSize(3); // 队列大小 poolExecutor.setQueueCapacity(5); // 线程最大空闲时间 poolExecutor.setKeepAliveSeconds(60); // 拒绝策略 poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); // 线程名称前缀 poolExecutor.setThreadNamePrefix("sendMessage-"); return poolExecutor; } }
@Service public class AsyncJob { @Async("taskExecutor") public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously: start." + Thread.currentThread().getName()); try { Thread.sleep(10 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Execute method asynchronously: end." + Thread.currentThread().getName()); } }
public class AsyncJobTest extends BaseTest { @Autowired private AsyncJob asyncJob; @Test void check_async() { System.out.println("check_async. " + Thread.currentThread().getName()); asyncJob.asyncMethodWithVoidReturnType(); try { Thread.sleep(30 * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果
揭秘 - 线程池
(1)通过@Async注解指定线程池的秘密
(2)使用Spring boot默认线程池(即:taskExecutor) 或者 SimpleAsyncTaskExecutor 的秘密
补充 - Spring Boot默认提供了名称为taskExecutor的线程池,所以我们在程序中不应该再自定义名称为taskExecutor的线程池
此处示例是通过@Autowire注解的方式注入线程池,区别于前面异步注解中指明线程池的方式
Future
如果@Async方法需要返回运行结果,可声明方法返回值为Future类型:
A、可以声明为常规的Java .util.concurrent. future类型
B、可以声明为Spring的org.springframework.util.concurrent.ListenableFuture类型
C、从Spring 4.2开始也可以声明为Java中的CompletableFuture
@Service public class AsyncJob { @Async public CompletableFuture<Integer> getEmployeeCount() { int count = 0; // ... return CompletableFuture.completedFuture(count); } }
扩展阅读
How To Do @Async in Spring | Baeldung
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】AI 的力量,开发者的翅膀:欢迎使用 AI 原生开发工具 TRAE
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
· 通过 Canvas 将后端发来的一帧帧图片渲染成“视频”的实现过程
· 当加密ID需要变成Guid:为什么我选择了AES-CBC而非GCM?
· 基于 epoll 的协程调度器——零基础深入浅出 C++20 协程
· 下划线字段在golang结构体中的应用
· SQL Server也能玩正则表达式?
· C#实现屏幕墙:同时监控多个电脑桌面(支持Windows、信创Linux、银河麒麟、统信UOS)
· 我的AI自学路线,可能对你有用
· 通过Canvas在网页中将后端发来的一帧帧图片渲染成“视频”的实现过程
· 如何做一个纯净版的ABP vNext 脚手架
· 告别 DOM 的旧时代:从零重塑 Web 渲染的未来