如何在项目中使用Spring异步调用注解@Async
本文主要介绍如何使用Spring框架提供的异步调用注解@Async,异步线程池配置、异常捕获处理。
开启@Async注解支持
使用@Async注解的之前,必须在项目中启动时调用@EnableAsync注解。比如通过定义一个JavaConfig文件:
@Configuration
@EnableAsync
public class AsyncConfig {
}
异步调用
使用@Async异步执行无返回值的任务
定义一个任务类AsyncTask,包含两个执行耗时任务的方法task1()、task2(),在两个方法上添加@Async
@Service
@Slf4j
public class AsyncTask {
@Async
public void task1() {
log.info("task1 start");
}
@Async
public void task2() {
log.info("task2 start");
}
}
定义测试类,串行调用AsyncTask.task1()和AsyncTask.task2()
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncTaskTest {
@Autowired
private AsyncTask asyncTask;
@Test
public void taskTest() {
log.info("taskTest start");
asyncTask.task1();
asyncTask.task2();
log.info("taskTest end");
}
}
从运行结果中看,task1和task2分别在两个不同的线程中执行:
INFO [15:18:29.182][main][com.breezek.demo.common.AsyncTaskTest][25]:taskTest start
INFO [15:18:29.188][main][com.breezek.demo.common.AsyncTaskTest][29]:taskTest end
INFO [15:18:29.192][task-1][com.breezek.demo.common.AsyncTask][29]:task2 start
INFO [15:18:29.192][task-2][com.breezek.demo.common.AsyncTask][24]:task1 start
异步回调
使用@Async异步执行有返回值的任务,并获取任务执行结果。
定义AsyncTask类,创建两个带返回值的异步方法,返回值类型为Future,task1执行时间5s,task2执行时间10s,在两个方法上添加@Async
@Service
@Slf4j
public class AsyncTask {
@Async
public Future<String> task1() throws InterruptedException {
log.info("task1 start");
Thread.sleep(5000L);
log.info("task1 end");
return new AsyncResult<>("task1 result");
}
@Async
public Future<Integer> task2() throws InterruptedException {
Integer abc = 1;
log.info("task2 start");
Thread.sleep(10000L);
log.info("task2 end");
return new AsyncResult<>(abc);
}
}
定义测试类,分别调用task1、task2,并等待task1和task2执行完毕
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class AsyncTaskTest {
@Autowired
private AsyncTask asyncTask;
@Test
public void taskTest() throws InterruptedException {
log.info("taskTest start");
Future<String> task1Future = asyncTask.task1();
Future<Integer> task2Future = asyncTask.task2();
// do something
for (int i = 0; i < 1000; i++) {
}
while (!task1Future.isDone() || !task2Future.isDone()) {
}
log.info("taskTest end");
}
}
运行结果:
INFO [17:54:24.554][main][com.breezek.demo.common.AsyncTaskTest][28]:taskTest start
INFO [17:54:24.566][task-1][com.breezek.demo.common.AsyncTask][27]:task1 start
INFO [17:54:24.566][task-2][com.breezek.demo.common.AsyncTask][36]:task2 start
INFO [17:54:29.569][task-1][com.breezek.demo.common.AsyncTask][29]:task1 end
INFO [17:54:34.570][task-2][com.breezek.demo.common.AsyncTask][38]:task2 end
INFO [17:54:34.570][main][com.breezek.demo.common.AsyncTaskTest][34]:taskTest end
可以看出来,main线程等待两个子线程执行完毕后再继续向下运行
使用@Async注解时,需要注意以下几点,否则异步调用不会生效:
- 异步方法不能定义为static类型
- 调用方法和异步方法不能定义在同一个类中
AsyncConfigurer配置
下面的代码中是如何配置异步调用使用的线程池、void返回值异常捕获处理
AsyncConfigurer接口是Spring提供的,我们定义JavaConfig时实现它:
@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
/**
* 配置线程池,减少在调用每个异步方法时创建和销毁线程所需的时间
*/
@Override
public Executor getAsyncExecutor() {
// 初始化Spring框架提供的线程池
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(10);
// 最大线程数
executor.setMaxPoolSize(20);
// 任务等待队列大小
executor.setQueueCapacity(10);
// 任务拒绝策略,如果线程池拒绝接受任务,使用调用线程执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 定义线程名称前缀
executor.setThreadNamePrefix("async-executor-");
// 调用线程池初始化方法,如果在getAsyncExecutor()加上了@Bean注解,这个方法可以不调用,因为ThreadPoolTaskExecutor实现了InitializingBean接口,Spring在初始化Bean时会调用InitializingBean.afterPropertiesSet()
executor.initialize();
return executor;
}
/**
* void返回值异步方法异常捕获处理
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
/**
* 异常捕获处理类
*/
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
log.error(String.format("Async method: %s has uncaught exception, params: %s.", method, JSON.toJSONString(params)), ex);
}
}
}
如何在项目中使用Spring异步调用注解@Async的更多相关文章
- Spring异步调用注解@Async的使用
1.pom依赖 <dependency> <groupId>org.springframework</groupId> <artifactId>spri ...
- web项目中 集合Spring&使用junit4测试Spring
web项目中 集合Spring 问题: 如果将 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(& ...
- 06_在web项目中集成Spring
在web项目中集成Spring 一.使用Servlet进行集成测试 1.直接在Servlet 加载Spring 配置文件 ApplicationContext applicationContext = ...
- Spring异步调用原理及SpringAop拦截器链原理
一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...
- 最近项目中使用Spring data jpa 踩过的坑
最近在做一个有关OA项目中使用spring data JPA 操作数据库,结果遇到了补个不可思议的麻烦.困惑了好久. 首先看一下问题吧,这就是当时测试“设置角色时,需要首先删除该用户已经拥有的角色时” ...
- 如何在maven项目中使用spring
今天开始在maven项目下加入spring. 边学习边截图. 在这个过程中我新建了一个hellospring的项目.于是乎从这个项目出发开始研究如何在maven项目中使用spring.鉴于网上的学习资 ...
- 如何在web项目中配置Spring的Ioc容器
在web项目中配置Spring的Ioc容器其实就是创建web应用的上下文(WebApplicationContext) 自定义要使用的IoC容器而不使用默认的XmlApplicationContext ...
- 如何在Spring异步调用中传递上下文
以下文章来源于aoho求索 ,作者aoho 1. 什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步 ...
- Spring Boot中实现异步调用之@Async
一.什么是异步调用 “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用 的语句返回结果 ...
随机推荐
- 多线程——Callable接口
package pers.aaa.callable; import java.util.concurrent.Callable; public class MyCallable implements ...
- 链表实现比较高效的删除倒数第k项
最近写链表不太顺,无限的段错误.今天中午写的链表删除倒数第k项,用的带尾节点的双向链表,感觉已经把效率提到最高了,还是超时,改了很多方法都不行,最 终决定看博客,发现原来是审题错了,阳历给的是以-1结 ...
- html使用空格的替代符号
替代符号就是在需要显示空格的地方加入替代符号,这些符号会被浏览器解释为空格显示. 空格的替代符号有以下几种: 名称 编号 描述 不断行的空白(1个字符宽度) 半个空白(1个字符宽度) ...
- 检查图片是否损坏、图片后缀是否与实际图片类型对应 - Python
图片工具 检查图片是否损坏 日常工作中,时常会需要用到图片,有时候图片在下载.解压过程中会损坏,而如果一张一张点击来检查就太不Cool了,因此我想大家都需要一个检查脚本: 测试图片,0.jpg是正常的 ...
- 利用Python制作二维码
利用简单的Python代码制作二维码 一.制作工具 安装Python环境 + PyCharm编译器. 二.电脑系统 本人win10 + Python3.7.0 + PyCharm. 三.写代码前先下载 ...
- Maven 梳理 - 常用三种archetype说明
archetype:原型的意思,可理解为Maven项目模板工具包 常用archetype 1.cocoon-22-archetype-webapp 2.maven-archetype-quicksta ...
- android字母索引实现ListView定位
最近闲的很,没什么事干 ,在玩手机的时间看到android系统自带的那个通讯录软件对联系人的快速定位功能. 感觉这个功能也比较实用自己就试着自己去实现. 虽然网络上还是有大牛封闭好了的框架,但是如果 ...
- .net core 3.0 Signalr - 03 使用MessagePack压缩传输内容
## MessagePack基础介绍 Signalr默认使用的是json形式传递数据,但是signalr提供了灵活的扩展,支持MessagePack形式序列化数据,以增加性能降低网络传输的效果,极大的 ...
- yum install php-gd 安装php gd库报错Error: php56w-common conflicts with php-common-5.3.3-48.el6_8.x86_64 大
yum install php-gd安装php gd库报错Error: php56w-common conflicts with php-common-5.3.3-48.el6_8.x86_64大概的 ...
- 快学Scala 第十二课 (抽象类, 抽象字段, 提前定义)
抽象类: Scala 抽象类中,抽象方法不需要使用abstract. 在子类中重写超类抽象方法时,不需要使用override. abstract class Person { def say(s: S ...