@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的用法和示例的更多相关文章

  1. 脚本引用中的defer和async的用法和区别

    之前的博客漫谈前端优化中的引用资源优化曾经提到过脚本引用异步设置defer.async,没有细说,这里展开一下,谈谈它们的作用和区别,先上张图来个针对没用过的小伙伴有个初始印象: 是的,就是在页面脚本 ...

  2. Async/Await 学习与示例

    参考:Async/await学习 es 7 提供了对 promise 对象的更好的操作,省去了很多丧心病狂的链式异步请求,promise 是回调地狱的福音,而 Async/Await 则是 promi ...

  3. Spring @Async实现异步调用示例

    什么是“异步调用”? “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果 ...

  4. Async异步编程入门示例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. C# 中[DllImport("user32.dll")]和extern用法和示例----转载

    原文:https://blog.csdn.net/michellehsiao/article/details/7629746         extern 修饰符用于声明在外部实现的方法.extern ...

  6. (转)Spring中@Async用法总结

     原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的: ...

  7. Spring中@Async用法总结

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3. ...

  8. Spring @Async使用方法总结

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  9. spring中使用@Async注解进行异步处理

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

随机推荐

  1. python 小兵(6)函数进阶

    阅读目录 函数参数-动态参数 名称空间 函数的嵌套 gloabal.nonlocal 回到顶部 函数参数-动态参数 之前我们说过传参,如果我们在传参数的时候不很清楚有哪些的时候,或者说给一个函数传了很 ...

  2. django之js模板插件artTemplate的使用

    安装: 方式1:artTemplate模板源码下载地址:https://aui.github.io/art-template/zh-cn/index.html 方式2:使用node.js进行安装:np ...

  3. 蓝桥杯试题 基础练习 2n皇后问题以及n皇后问题

    在学习2n皇后之前,我们应该认识一下n皇后问题: 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上.你的任务是,对于 ...

  4. 后缀自动机 (SAM)

    后缀自动机 定义 定义 SAM 为一个有限状态自动机,接受且仅接受 \(S\) 的一个后缀. 同时,SAM 是这样的自动机中最小的那个,其中状态数至多为 \(2n - 1\),转移数至多为 \(3n ...

  5. 在Rainbond中实现数据库结构自动化升级

    Rainbond 这款产品一直致力于打通企业应用交付的全流程,这个流程中不可或缺的一环是企业应用的不断升级.迭代.Rainbond 特有的能力,是可以将囊括多个服务组件的企业应用系统进行打包,并执行一 ...

  6. Java 变量的声明及初始化

    格式: 数据类型 变量名字1 , 变量名字2 ,--变量名字n ; 案例: int i 声明了一个整形的变量. double d 声明了一个double数据类型的变量 float  f 声明了一个fl ...

  7. 【论文阅读笔记】-针对RSA的短解密指数的密码学分析(Cryptanalysis of Short RSA Secret Exponents)

    目录 1. 介绍 polynomially larger 2. 连分数背景知识 3. 连分数算法 4. 连分数算法在RSA中的应用 5. 例子 6. 对RSA连分数攻击的反制 7. 对于攻击的改进 8 ...

  8. [TJOI2013] 奖学金

    代码: #include<bits/stdc++.h> using namespace std; long long n,c,ff,ans; long long suma[200010], ...

  9. Solution -「NOI.AC 省选膜你赛」寄蒜几盒

    题目 题意简述   给定一个含有 \(n\) 个顶点的凸多边形( \(n\) 是偶数),对于每一对相对的边(即中间有 \(\frac{n}2-1\) 条其它边),延长它们以将平面分割为多块,并把包含原 ...

  10. Solution -「Gym 102798K」Tree Tweaking

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\),求任意重排 \(p_{l..r}\) 的元素后,将 \(\{p_n\}\) 依次插入二叉搜索树 ...