@Async的用法和示例
@Async 注解的用法和示例
背景
通常,在Java中的方法调用都是同步调用,比如在A方法中调用了B方法,则在A调用B方法之后,必须等待B方法执行并返回后,A方法才可以继续往下执行。这样容易出现的一个问题就是如果B方法执行时间较长,则可能会导致调用A的请求响应迟缓,为了解决这种问题,可以使用Spirng的注解@Async来用异步调用的方式处理,当然也会有别的多线程方式解决此类问题,本文主要分析@Async在解决此类问题时的用法以及具体的示例。
异步调用
比如方法A调用方法B,如果B是一个异步方法,则A方法在调用B方法之后,不用等待B方法执行完成,而是直接往下继续执行别的代码。
@Async介绍
在Spring中,使用@Async标注某方法,可以使该方法变成异步方法,这些方法在被调用的时候,将会在独立的线程中进行执行,调用者不需等待该方法执行完成。
在Spring中启用@Async
使用@EnableAsync
@Slf4j
@SpringBootApplication
@ComponentScan(basePackages = {"com.kaesar.spring"})
@EnableAsync // 开启异步调用
public class Application {
public static void main(String[] args) {
log.info("spring boot开始启动...");
ApplicationContext ctx = SpringApplication.run(Application.class, args);
String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
for (String profile : activeProfiles) {
log.info("当前环境为:" + profile);
}
log.info("spring boot启动成功...");
}
}
示例一:基本使用方式
在方法上添加@Async注解
/**
* 异步方法
* 默认情况下,Spring 使用 SimpleAsyncTaskExecutor 去执行这些异步方法(此执行器没有限制线程数)。
* 此默认值可以从两个层级进行覆盖:
* 方法级别
* 应用级别
*/
@Async
public void test2() {
try {
log.info(Thread.currentThread().getName() + " in test2, before sleep.");
Thread.sleep(2000);
log.info(Thread.currentThread().getName() + " in test2, after sleep.");
} catch (InterruptedException e) {
log.error("sleep error.");
}
}
调用异步方法
/**
* 调用不同类的异步方法
*/
public void func1() {
log.info("before call async function.");
asyncService.test2();
log.info("after call async function.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
log.error("sleep error.");
}
log.info("func end.");
}
执行结果
从执行结果可以看出,main线程中的func1方法在调用异步方法test2后,没有等待test2方法执行完成,直接执行后面的代码。
示例二:在同一个类中调用异步方法
方法func2和上面的异步方法test2方法在同一个类中
从执行结果可知,main线程中的func2方法在调用异步方法test2方法后,等待test2方法执行完后,才继续往后执行。
示例三:异步方法是static方法
异步方法test3是一个static方法
/**
* 异步方法不能是 static 方法,不然注解失效
*/
@Async
public static void test3() {
try {
log.info(Thread.currentThread().getName() + " in test3, before sleep.");
Thread.sleep(2000);
log.info(Thread.currentThread().getName() + " in test3, after sleep.");
} catch (InterruptedException e) {
log.error("sleep error.");
}
}
调用test3的方法
/**
* 调用不同类的异步方法,异步方法是 static 方法
*/
public void func3() {
log.info(Thread.currentThread().getName() + ": before call async function.");
AsyncService.test3();
log.info(Thread.currentThread().getName() + ": after call async function.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
log.error("sleep error.");
}
log.info(Thread.currentThread().getName() + ": func end.");
}
执行结果。可以看出在static方法上添加@Async注解,当调用该方法时并没有新启用一个线程单独执行,而是按顺序执行代码,说明异步无效。
示例四:在方法级别上修改默认的执行器
自定义一个线程池执行器代替默认的执行器
自定义的线程池执行器
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 自定义线程池
*/
@Configuration
public class AsyncConfig {
private static final int MAX_POOL_SIZE = 10;
private static final int CORE_POOL_SIZE = 5;
@Bean("asyncTaskExecutor")
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");
asyncTaskExecutor.initialize();
return asyncTaskExecutor;
}
}
异步方法上使用自定义的执行器
/**
* 在方法级别上修改默认的执行器
*/
@Async("asyncTaskExecutor")
public void test4() {
try {
log.info(Thread.currentThread().getName() + ": in test4, before sleep.");
Thread.sleep(2000);
log.info(Thread.currentThread().getName() + ": in test4, after sleep.");
} catch (InterruptedException e) {
log.error("sleep error.");
}
}
调用test4异步方法
/**
* 调用不同类的异步方法
*/
public void func4() {
log.info(Thread.currentThread().getName() + ": before call async function.");
asyncService.test4();
log.info(Thread.currentThread().getName() + ": after call async function.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
log.error("sleep error.");
}
log.info(Thread.currentThread().getName() + ": func end.");
}
从执行结果可以看出,@Async注解声明使用指定的自定义的异步执行器,已经替换了默认的执行器。而且调用异步方法的main线程没有等待异步方法的执行。
说明:新建自定义的执行器后,注解@Async默认就会替换成自定义的执行器,所以在@Async注解上可以不用指定。
\(1.01^{365} ≈ 37.7834343329\)
\(0.99^{365} ≈ 0.02551796445\)
相信坚持的力量!
@Async的用法和示例的更多相关文章
- 脚本引用中的defer和async的用法和区别
之前的博客漫谈前端优化中的引用资源优化曾经提到过脚本引用异步设置defer.async,没有细说,这里展开一下,谈谈它们的作用和区别,先上张图来个针对没用过的小伙伴有个初始印象: 是的,就是在页面脚本 ...
- Async/Await 学习与示例
参考:Async/await学习 es 7 提供了对 promise 对象的更好的操作,省去了很多丧心病狂的链式异步请求,promise 是回调地狱的福音,而 Async/Await 则是 promi ...
- Spring @Async实现异步调用示例
什么是“异步调用”? “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果 ...
- Async异步编程入门示例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- C# 中[DllImport("user32.dll")]和extern用法和示例----转载
原文:https://blog.csdn.net/michellehsiao/article/details/7629746 extern 修饰符用于声明在外部实现的方法.extern ...
- (转)Spring中@Async用法总结
原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的: ...
- Spring中@Async用法总结
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3. ...
- Spring @Async使用方法总结
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...
- spring中使用@Async注解进行异步处理
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...
随机推荐
- Spring系列8:bean的作用域
本文内容 bean定义信息的意义 介绍6种bean的作用域 bean定义信息的意义 Spring中区分下类.类定义信息,类实例对象的概念?不容易理解,以餐馆中点炒饭为例. 类: 相当于你看到菜单上炒饭 ...
- 张高兴的 .NET IoT 入门指南:(七)制作一个气象站
距离上一篇<张高兴的 .NET Core IoT 入门指南>系列博客的发布已经过去 2 年的时间了,2 年的时间 .NET 版本发生了巨大的变化,.NET Core 也已不复存在,因此本系 ...
- 300iq Contest 1 C Cool Pairs
为了构造时恰好取到 \(k\) 对时的方便,可以考虑将 \(a\) 设为互不相同的 \(n\) 个数,这样对每个 \(b\) 的取值对答案的贡献就是可以通过调整变成任意值的. 因为要尽可能造成贡献,因 ...
- CF1408G Clusterization Counting
首先,我们需要给一个连通块找到一个直观的合法判定解. 那么我们必须以一种直观的方式将边按照权值分开,这样才能直观地判定一个合法的组. 一个常见的方式是将边从小到大依次加入进来,那么在任意时刻图上存在的 ...
- 前后端数据json交换的问题
问题1:前端发送给后端数据了,后端也接收到了,后端同时返回数据给前端了,但是前端的ajax请求中的success(data){}中的方法不执行 解决:排查了很多问题,结果都一一排除了,最后发现后端发送 ...
- java命令-(学习)jstack 工具
一.介绍 jstack是java虚拟机自带的一种堆栈跟踪工具.jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项&qu ...
- Java线程--Semaphore使用
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11872132.html Java线程--Semaphore使用 Semaphore是信号量, ...
- 简单仿京东"筛选"界面 双导航栏控制器共存 by Nicky.Tsui
大概就是这么一个效果 如图.大概可以看到,"筛选"视图后面有一层视图盖住了后面原来的视图 那么我们可以通过加一个view到导航栏控制器的view里面来实现 //该view作为全局变 ...
- mapTest
import java.util.*;public class mapTest { public static void main(String[] args) throws Exception{ L ...
- pytest(4)-测试用例执行顺序
前言 上一篇文章我们讲了在pytest中测试用例的命名规则,那么在pytest中又是以怎样的顺序执行测试用例的呢? 在unittest框架中,默认按照ACSII码的顺序加载测试用例并执行,顺序为:09 ...