浅谈Spring @Async异步线程池用法总结
发布时间 - 2026-01-11 02:30:31 点击率:次本文介绍了Spring @Async异步线程池用法总结,分享给大家,希望对大家有帮助

1. TaskExecutor
spring异步线程池的接口类,其实质是Java.util.concurrent.Executor
Spring 已经实现的异常线程池:
1. SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。
2. SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方
3. ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
4. SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类
5. ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装
2. @Async
spring对过@Async定义异步任务
异步的方法有3种
1. 最简单的异步调用,返回值为void
2. 带参数的异步调用 异步方法可以传入参数
3. 异常调用返回Future
详细见代码:
@Component
public class AsyncDemo {
private static final Logger log = LoggerFactory.getLogger(AsyncDemo.class);
/**
* 最简单的异步调用,返回值为void
*/
@Async
public void asyncInvokeSimplest() {
log.info("asyncSimplest");
}
/**
* 带参数的异步调用 异步方法可以传入参数
*
* @param s
*/
@Async
public void asyncInvokeWithParameter(String s) {
log.info("asyncInvokeWithParameter, parementer={}", s);
}
/**
* 异常调用返回Future
*
* @param i
* @return
*/
@Async
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture, parementer={}", i);
Future<String> future;
try {
Thread.sleep(1000 * 1);
future = new AsyncResult<String>("success:" + i);
} catch (InterruptedException e) {
future = new AsyncResult<String>("error");
}
return future;
}
}
以上的异步方法和普通的方法调用相同
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithException("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());
3. Spring 开启异步配置
Spring有两种方法启动配置
1. 注解
2. XML
3.1 通过注解实现
要启动异常方法还需要以下配置
1. @EnableAsync 此注解开户异步调用功能
2. public AsyncTaskExecutor taskExecutor() 方法自定义自己的线程池,线程池前缀”Anno-Executor”。如果不定义,则使用系统默认的线程池。
@SpringBootApplication
@EnableAsync // 启动异步调用
public class AsyncApplicationWithAnnotation {
private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAnnotation.class);
/**
* 自定义异步线程池
* @return
*/
@Bean
public AsyncTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("Anno-Executor");
executor.setMaxPoolSize(10);
// 设置拒绝策略
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// .....
}
});
// 使用预定义的异常处理类
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
public static void main(String[] args) {
log.info("Start AsyncApplication.. ");
SpringApplication.run(AsyncApplicationWithAnnotation.class, args);
}
}
以上的异常方法和普通的方法调用相同
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithAnnotation.class)
public class AsyncApplicationWithAnnotationTests {
@Autowired
private AsyncDemo asyncDemo;
@Test
public void contextLoads() throws InterruptedException, ExecutionException {
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithParameter("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());
}
}
执行测试用例,输出内容如下:
可以看出主线程的名称为main; 异步方法则使用 Anno-Executor1,可见异常线程池起作用了
2017-03-28 20:00:07.731 INFO 5144 --- [ Anno-Executor1] c.hry.spring.async.annotation.AsyncDemo : asyncSimplest 2017-03-28 20:00:07.732 INFO 5144 --- [ Anno-Executor1] c.hry.spring.async.annotation.AsyncDemo : asyncInvokeWithParameter, parementer=test 2017-03-28 20:00:07.751 INFO 5144 --- [ Anno-Executor1] c.hry.spring.async.annotation.AsyncDemo : asyncInvokeReturnFuture, parementer=100 success:100 2017-03-28 20:00:08.757 INFO 5144 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@47af7f3d: startup date [Tue Mar 28 20:00:06 CST 2017]; root of context hierarchy
3.2 通过XML实现
Bean文件配置: spring_async.xml
1. 线程的前缀为xmlExecutor
2. 启动异步线程池配置
<!-- 等价于 @EnableAsync, executor指定线程池 -->
<task:annotation-driven executor="xmlExecutor"/>
<!-- id指定线程池产生线程名称的前缀 -->
<task:executor
id="xmlExecutor"
pool-size="5-25"
queue-capacity="100"
keep-alive="120"
rejection-policy="CALLER_RUNS"/>
线程池参数说明
1. ‘id' : 线程的名称的前缀
2. ‘pool-size':线程池的大小。支持范围”min-max”和固定值(此时线程池core和max sizes相同)
3. ‘queue-capacity' :排队队列长度
○ The main idea is that when a task is submitted, the executor will first try to use a free thread if the number of active threads is currently less than the core size.
○ If the core size has been reached, then the task will be added to the queue as long as its capacity has not yet been reached.
○ Only then, if the queue's capacity has been reached, will the executor create a new thread beyond the core size.
○ If the max size has also been reached, then the executor will reject the task.
○ By default, the queue is unbounded, but this is rarely the desired configuration because it can lead to OutOfMemoryErrors if enough tasks are added to that queue while all pool threads are busy.
4. ‘rejection-policy': 对拒绝的任务处理策略
○ In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
○ In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
○ In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
○ In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)
5. ‘keep-alive' : 线程保活时间(单位秒)
setting determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess threads will get terminated. A time value of zero will cause excess threads to terminate immediately after executing a task without remaining follow-up work in the task queue()
异步线程池
@SpringBootApplication
@ImportResource("classpath:/async/spring_async.xml")
public class AsyncApplicationWithXML {
private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithXML.class);
public static void main(String[] args) {
log.info("Start AsyncApplication.. ");
SpringApplication.run(AsyncApplicationWithXML.class, args);
}
}
测试用例
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithXML.class)
public class AsyncApplicationWithXMLTest {
@Autowired
private AsyncDemo asyncDemo;
@Test
public void contextLoads() throws InterruptedException, ExecutionException {
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithParameter("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());
}
}
运行测试用例,输出内容如下:
可以看出主线程的名称为main; 异步方法则使用 xmlExecutor-x,可见异常线程池起作用了
2017-03-28 20:12:10.540 INFO 12948 --- [ main] c.h.s.a.xml.AsyncApplicationWithXMLTest : Started AsyncApplicationWithXMLTest in 1.441 seconds (JVM running for 2.201) 2017-03-28 20:12:10.718 INFO 12948 --- [ xmlExecutor-2] com.hry.spring.async.xml.AsyncDemo : asyncInvokeWithParameter, parementer=test 2017-03-28 20:12:10.721 INFO 12948 --- [ xmlExecutor-1] com.hry.spring.async.xml.AsyncDemo : asyncSimplest 2017-03-28 20:12:10.722 INFO 12948 --- [ xmlExecutor-3] com.hry.spring.async.xml.AsyncDemo : asyncInvokeReturnFuture, parementer=100 success:100 2017-03-28 20:12:11.729 INFO 12948 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@71809907: startup date [Tue Mar 28 20:12:09 CST 2017]; root of context hierarchy
4. 对异步方法的异常处理
在调用方法时,可能出现方法中抛出异常的情况。在异步中主要有有两种异常处理方法:
1. 对于方法返回值是Futrue的异步方法: a) 一种是在调用future的get时捕获异常; b) 在异常方法中直接捕获异常
2. 对于返回值是void的异步方法:通过AsyncUncaughtExceptionHandler处理异常
AsyncExceptionDemo:
@Component
public class AsyncExceptionDemo {
private static final Logger log = LoggerFactory.getLogger(AsyncExceptionDemo.class);
/**
* 最简单的异步调用,返回值为void
*/
@Async
public void asyncInvokeSimplest() {
log.info("asyncSimplest");
}
/**
* 带参数的异步调用 异步方法可以传入参数
* 对于返回值是void,异常会被AsyncUncaughtExceptionHandler处理掉
* @param s
*/
@Async
public void asyncInvokeWithException(String s) {
log.info("asyncInvokeWithParameter, parementer={}", s);
throw new IllegalArgumentException(s);
}
/**
* 异常调用返回Future
* 对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理
* 或者在调用方在调用Futrue.get时捕获异常进行处理
*
* @param i
* @return
*/
@Async
public Future<String> asyncInvokeReturnFuture(int i) {
log.info("asyncInvokeReturnFuture, parementer={}", i);
Future<String> future;
try {
Thread.sleep(1000 * 1);
future = new AsyncResult<String>("success:" + i);
throw new IllegalArgumentException("a");
} catch (InterruptedException e) {
future = new AsyncResult<String>("error");
} catch(IllegalArgumentException e){
future = new AsyncResult<String>("error-IllegalArgumentException");
}
return future;
}
}
实现AsyncConfigurer接口对异常线程池更加细粒度的控制
a) 创建线程自己的线程池
b) 对void方法抛出的异常处理的类AsyncUncaughtExceptionHandler
/**
* 通过实现AsyncConfigurer自定义异常线程池,包含异常处理
*
* @author hry
*
*/
@Service
public class MyAsyncConfigurer implements AsyncConfigurer{
private static final Logger log = LoggerFactory.getLogger(MyAsyncConfigurer.class);
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(1);
threadPool.setMaxPoolSize(1);
threadPool.setWaitForTasksToCompleteOnShutdown(true);
threadPool.setAwaitTerminationSeconds(60 * 15);
threadPool.setThreadNamePrefix("MyAsync-");
threadPool.initialize();
return threadPool;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncExceptionHandler();
}
/**
* 自定义异常处理类
* @author hry
*
*/
class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.info("Exception message - " + throwable.getMessage());
log.info("Method name - " + method.getName());
for (Object param : obj) {
log.info("Parameter value - " + param);
}
}
}
}
@SpringBootApplication
@EnableAsync // 启动异步调用
public class AsyncApplicationWithAsyncConfigurer {
private static final Logger log = LoggerFactory.getLogger(AsyncApplicationWithAsyncConfigurer.class);
public static void main(String[] args) {
log.info("Start AsyncApplication.. ");
SpringApplication.run(AsyncApplicationWithAsyncConfigurer.class, args);
}
}
测试代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes=AsyncApplicationWithAsyncConfigurer.class)
public class AsyncApplicationWithAsyncConfigurerTests {
@Autowired
private AsyncExceptionDemo asyncDemo;
@Test
public void contextLoads() throws InterruptedException, ExecutionException {
asyncDemo.asyncInvokeSimplest();
asyncDemo.asyncInvokeWithException("test");
Future<String> future = asyncDemo.asyncInvokeReturnFuture(100);
System.out.println(future.get());
}
}
运行测试用例
MyAsyncConfigurer 捕获AsyncExceptionDemo 对象在调用asyncInvokeWithException的异常 2017-04-02 16:01:45.591 INFO 11152 --- [ MyAsync-1] c.h.s.a.exception.AsyncExceptionDemo : asyncSimplest 2017-04-02 16:01:45.605 INFO 11152 --- [ MyAsync-1] c.h.s.a.exception.AsyncExceptionDemo : asyncInvokeWithParameter, parementer=test 2017-04-02 16:01:45.608 INFO 11152 --- [ MyAsync-1] c.h.s.async.exception.MyAsyncConfigurer : Exception message - test 2017-04-02 16:01:45.608 INFO 11152 --- [ MyAsync-1] c.h.s.async.exception.MyAsyncConfigurer : Method name - asyncInvokeWithException 2017-04-02 16:01:45.608 INFO 11152 --- [ MyAsync-1] c.h.s.async.exception.MyAsyncConfigurer : Parameter value - test 2017-04-02 16:01:45.608 INFO 11152 --- [ MyAsync-1] c.h.s.a.exception.AsyncExceptionDemo : asyncInvokeReturnFuture, parementer=100 error-IllegalArgumentException 2017-04-02 16:01:46.656 INFO 11152 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@47af7f3d: startup date [Sun Apr 02 16:01:44 CST 2017]; root of context hierarchy
5. 源码地址
代码的GITHUB地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# spring异步线程池
# spring
# async
# 线程池
# Spring中@Async用法详解及简单实例
# 关于Spring注解@Async引发其他注解失效的解决
# JAVA 中Spring的@Async用法总结
# Spring中@Async注解执行异步任务的方法
# Spring @Async 的使用与实现的示例代码
# Spring处理@Async导致的循环依赖失败问题的方案详解
# Java Spring的@Async的使用及注意事项示例总结
# 自定义
# 自己的
# 返回值
# 最简单
# 值为
# 可以看出
# 有两种
# 抛出
# 其实质
# 是在
# 不需要
# 推荐使用
# 适用于
# 给大家
# 此类
# 还需要
# 只是一个
# 可能出现
# 创建一个
# 使用这个
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
猎豹浏览器开发者工具怎么打开 猎豹浏览器F12调试工具使用【前端必备】
黑客如何通过漏洞一步步攻陷网站服务器?
Laravel如何与Docker(Sail)协同开发?(环境搭建教程)
教学论文网站制作软件有哪些,写论文用什么软件
?
Python文件流缓冲机制_IO性能解析【教程】
Linux安全能力提升路径_长期防护思维说明【指导】
北京的网站制作公司有哪些,哪个视频网站最好?
Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理
Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法
Laravel与Inertia.js怎么结合_使用Laravel和Inertia构建现代单页应用
做企业网站制作流程,企业网站制作基本流程有哪些?
Google浏览器为什么这么卡 Google浏览器提速优化设置步骤【方法】
JS弹性运动实现方法分析
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
如何快速生成高效建站系统源代码?
详解Oracle修改字段类型方法总结
php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】
如何正确选择百度移动适配建站域名?
详解CentOS6.5 安装 MySQL5.1.71的方法
Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议
三星网站视频制作教程下载,三星w23网页如何全屏?
如何快速选择适合个人网站的云服务器配置?
如何确保西部建站助手FTP传输的安全性?
Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
如何在万网开始建站?分步指南解析
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】
edge浏览器无法安装扩展 edge浏览器插件安装失败【解决方法】
Laravel怎么发送邮件_Laravel Mail类SMTP配置教程
javascript中闭包概念与用法深入理解
Laravel怎么在Controller之外的地方验证数据
如何正确下载安装西数主机建站助手?
如何在局域网内绑定自建网站域名?
Laravel如何使用模型观察者?(Observer代码示例)
nodejs redis 发布订阅机制封装实现方法及实例代码
Windows Hello人脸识别突然无法使用
如何在景安云服务器上绑定域名并配置虚拟主机?
企业网站制作这些问题要关注
Win11怎样安装网易有道词典_Win11安装词典教程【步骤】
google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤
HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】
北京网站制作的公司有哪些,北京白云观官方网站?
Laravel用户密码怎么加密_Laravel Hash门面使用教程
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
JavaScript实现Fly Bird小游戏
深圳网站制作平台,深圳市做网站好的公司有哪些?
b2c电商网站制作流程,b2c水平综合的电商平台?
下一篇:运维安全审计系统属于什么品目
下一篇:运维安全审计系统属于什么品目

