Spring中@Async注解的使用

news2024/12/23 22:50:37

一、应用场景

1、同步调用
通常,在Java中的方法调用都是同步调用,比如在A方法中调用了B方法,则在A调用B方法之后,必须等待B方法执行并返回后,A方法才可以继续往下执行。

这样容易出现的一个问题就是如果B方法执行时间较长,则可能会导致调用A的请求响应迟缓 或者超时,验证影响用户体验。

为了解决这种问题,可以使用Spirng的注解@Async来用异步调用的方式处理。

2、异步调用
比如方法A调用方法B,如果B是一个异步方法,则A方法在调用B方法之后,不用等待B方法执行完成,而是直接往下继续执行别的代码。

这样,接口响应速度就会比较快。场景示例:商品库存更新接口,更新成功后,需要发送通知邮件,而接口的返回和邮件是否发送成功无关,那发送邮件这个步骤就可以写成1个异步方法进行调用。

二、含义

  1. 在方法上使用该@Async注解,申明该方法是一个异步任务;
  2. 在类上面使用该@Async注解,申明该类中的所有方法都是异步任务;
  3. 使用此注解的方法的类对象,必须是spring管理下的bean对象;
  4. 要想使用异步任务,需要在主类上开启异步配置,即,配置上@EnableAsync注解;

三、使用步骤

1、启动类中增加@EnableAsync

以Spring boot 为例,启动类中增加@EnableAsync:

@EnableAsync  // 开启异步调用
@SpringBootApplication
public class Application{
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
2、方法上加@Async注解

@Component //  添加注解表示这个类本身要被Spring管理
public class MyAsyncTask {
	/**
	* 异步方法
	* 默认情况下,Spring 使用 SimpleAsyncTaskExecutor 去执行这些异步方法(此执行器没有限制线程数)。
	* 此默认值可以从两个层级进行覆盖:
	* 方法级别
	* 应用级别
	*/
     @Async  // 添加注解表示这个方法要异步执行
    public void testSync() {
        TimeUnit.SECONDS.sleep(10);
        System.out.println("testSync");
    }
}
3、测试
@Service
public class TestService {
	
	@Autowired
    private MyAsyncTask myAsyncTask;

    public String sync() {
    	// 调用MyAsyncTask类的异步方法testSync
        myAsyncTask.testSync();
        return "sync";
    }

}

正常情况下,执行testSync 方法会阻塞10秒。但是,可以看到,sync 方法调用 testSync 后直接立即返回,并没有等待testSync 方法阻塞10秒,这就是异步效果。

其原理是,在默认情况下开启了一个线程前缀为 task-x 的新线程在执行任务

三、异步任务的返回结果

点开@Async 注解源码,可以看到这样一句话:
在这里插入图片描述

In terms of target method signatures, any parameter types are supported. However, the return type is constrained to either void or java.util.concurrent.Future.

翻译:
在目标方法(说到目标方法,说到 target,说明存在一个代理对象)的签名中,入参是任何类型都支持的。但是,返回类型被限制为 void 或者 Future

所以,异步方法的返回值只能有两种:void 或者 Future。
我们有时需要异步方法返回结果,有时不需要。
不需要返回结果的比较简单,和上面的示例一样,就不多说了。
需要接收返回结果的示例如下:

// 异步方法
@Async
public Future<Map<Long, List>> queryMap(List ids) {
    List<> result = businessService.queryMap(ids);
    ..............
    Map<Long, List> resultMap = Maps.newHashMap();
    ...
    return new AsyncResult<>(resultMap);
}

调用异步方法的示例:

public Map<Long, List> asyncProcess(List<BindDeviceDO> bindDevices,List<BindStaffDO> bindStaffs, String dccId) {
        Map<Long, List> finalMap =null;
        // 返回值:
        Future<Map<Long, List>> asyncResult = MyService.queryMap(ids);
        try {
            finalMap = asyncResult.get();
        } catch (Exception e) {
            ...
        }
        return finalMap;
}

可以看到,其实返回值是可以返回任何类型的,只是说,需要用 java.util.concurrent.Future类来包装一下, 然后结果可以通过Future类的get方法获取。Future:这里V可以是任何类型。

四、自定义线程池

点开@Async注解源码,可以看到,只有1个value 属性
在这里插入图片描述
这个value属性就是用来传线程池的bean名称的,相当于指定线程池的意思。

上面我们提到了如果@Async不指定任何value值,那么Spring 使用默认的线程池/执行器 去执行这些异步方法,这个默认的执行器就是:SimpleAsyncTaskExecutor

这个执行器有什么特征呢?

默认核心线程数:8,
最大线程数:Integer.MAX_VALUE,
队列使用 LinkedBlockingQueue,
容量是:Integer.MAX_VALUE,
空闲线程保留时间:60s,
线程池拒绝策略:AbortPolicy

最大线程数是Integer的最大值,队列使用的是无界队列,从最大线程数和队列来看,并发情况下,这个默认线程池是有内存溢出风险的。

所以,如果业务并发量大,我们最好使用自定义线程池

如何自定义线程池,步骤如下:

1、配置文件自定义配置参数
spring:
  task:
    execution:
      pool:
		# 最大线程数
        max-size: 10
        # 核心线程数
        core-size: 5
        # 空闲线程存活时间
        keep-alive: 5s
        # 队列长度
        queue-capacity: 1000
        # 线程名前缀
        thread-name-prefix: task_name
2、编写配置类
@Configuration
@Data
public class ExecutorConfig{
    /**
     * 核心线程
     */
    private int corePoolSize;
    /**
     * 最大线程
     */
    private int maxPoolSize;
    /**
     * 队列容量
     */
    private int queueCapacity;
    /**
     * 保持时间
     */
    private int keepAliveSeconds;
    /**
     * 名称前缀
     */
    private String preFix;
 
    @Bean("MyExecutor")
    public Executor myExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setThreadNamePrefix(preFix);
        executor.setRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy());
        executor.initialize();
        return executor;
    }
}
3、异步方法中引用
@Component
public class MyAsyncTask {

     @Async("MyExecutor") //使用自定义的线程池(执行器)
    public void asyncCpsItemImportTask(Long platformId, String jsonList){
        //...具体业务逻辑
    }
}

五、注意事项

1、无法调用同类中的@Async的方法

@Async 的原理是通过 Spring AOP 动态代理 的方式来实现的,如果a方法调用它同类中的标注@Async的b方法,是不会异步执行的,因为从a方法进入调用的都是该类对象本身,不会进入代理类。
因此,相同类中的方法调用带@Async的方法是无法异步的,这种情况仍然是同步。

@Service
public class TestService {
  
  
  public String sync() {
    // 调用同类中的异步方法testSync,异步无效果
    testSync();
    return "sync";
  }
  
  /**
   * 异步方法 testSync
   */
  @Async 
  public void testSync() {
    TimeUnit.SECONDS.sleep(10);
    System.out.println("testSync");
  }

}
2、异步方法是static方法,@Async注解无效果
  /**
   * 异步方法不能是 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.");
    }
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何避免“非正常专利申请”?!

近年来&#xff0c;专利数量多但质量不优的现象时而发生。对此&#xff0c;国家知识产权局开始严打非正常申请专利行为。而就在前不久&#xff0c;上海、甘肃等地也出台了相应的地方惩戒措施以打击非正常专利申请&#xff0c;这也反映出未来国家对于专利质量有着更高要求的趋势…

ubuntu 18.04 安装搜狗拼音输入法(没有坑)

本文参考&#xff1a;https://blog.csdn.net/weixin_44497198/article/details/126133691 最近在使用 ubuntu18.04 发现自带的中文输入法太难用了&#xff0c;于是想起装一个搜狗拼音输入法&#xff0c;但是按照搜狗官方的教程安装失败&#xff0c;安装成功了也是不稳定&#x…

钉钉机器人报警设置

钉钉机器人报警设置 1. 钉钉机器人相关设置 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 2. 添加机器人 3. 选择自定义机器人 4. 选择一个安全标签 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 5. 添加完生成一个webhook…

小蓝本 第一本 《因式分解技巧》 第五章 十字相乘 笔记(第五天)

小蓝本 第一本 《因式分解技巧》 第五章 十字相乘 笔记&#xff08;第五天&#xff09;前言十字相乘研究对象类型普通二次三项式基本形式分解步骤注意二次齐次式基本形式分组步骤注意系数和为0的普通二次三项式习题5题目题解前言 今天的干货来了&#xff0c;十字相乘。 十字相…

【JS】事件基础

JavaScript事件基础事件的概述事件三要素常见的事件事件的调用在script标签中调用在元素中调用鼠标事件onclick事件onmouseover和onmouseoutonmousedown和onmouseup页面事件onloadonbeforeunloadthis其他事件事件的概述 事件操作是JavaScript的核心。 用户进行操作时&#xff0…

疫情在家用Python搞副业,也能月入10000+

下班副业实现经济自由的时候&#xff0c;你还在床上躺着&#xff0c;天天摆烂吗&#xff1f;这样的生活真的是你想要的吗&#xff1f; 疫情在家接一些Python相关的小单子&#xff0c;既能给自己练手&#xff0c;还能赚是真香 从零基础开始真的一台电脑和一部手机就可以✅ 一…

NC65 计算人员离退休的天数和日期(数据库 sql server)

最近公司需要人力资源部需要写一张报表&#xff0c;计算人员距离退休的天数和日期&#xff0c;现附上自己写是sql脚本&#xff08;仅供参考&#xff09;&#xff0c;如下&#xff1a; select a.pk_psndoc,--员工信息主键a.code …

程序员快速成长的核心原则

如何快速成长、持续成长、提升技术&#xff0c;是每一个程序员都绕不开的话题。 当你还在困惑职业发展方向时&#xff0c;别人已经找好了接单平台开始兼职&#xff1b;当你还在苦恼bug修不好时&#xff0c;别人已经可以承接整个软件外包项目了&#xff1b;当你还在思考怎么让技…

MongoDB 命令行操作

通过 MongoDB 数据库安装详细教程 安装完成了MongoDB&#xff0c;MySQL数据库是通过sql命令操作数据&#xff0c;而MongoDB是通过类Javascript函数的查询方式进行数据库的操作&#xff0c;在使用MongoDB来操作数据库之前先来简单的了解MongoDB操作注意&#xff1a; MongoDB数据…

使用线性光耦合器的模拟隔离

介绍 模拟隔离仍然广泛应用于电机驱动、功率监测等&#xff0c;其中应用通常使用廉价的模拟电压控制来进行速度、强度或其他调整。 HCNR201/200模拟光耦合器通常被添加到&#xff0c;用于隔离应用电路的前端模块中的模拟信号。光耦合器将放置在模拟输入和A/D转换器之间&#…

C++list

1. list的介绍及使用 1.1 list的介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xff0c;并且该容器可以前后双向迭代。 2. list的底层是双向链表结构&#xff0c;双向链表中每个元素存储在互不相关的独立节点中&#xff0c;在节点中通过指针指向其…

外包出去找工作被歧视,投几个简历都说介意外包,不考虑外包。

说起外包这个话题&#xff0c;一直是职场的热门话题。 关于外包&#xff0c;最多被人讨论的就是歧视方面的。比如&#xff0c;关于门禁权限方面的歧视、关于语言交流上的歧视、关于福利上的歧视等等。 01 外包被歧视的情况确实存在 网传有一腾讯外包员工在脉脉上吐槽自己遭受…

python--内置高阶函数、异常处理;模块与包以及python基础部分的总结

文章目录一、内置高阶函数二、异常处理异常处理机制抛出异常三、模块与包python基础部分的总结一、sort()与sorted()函数的区别二、深拷贝和浅拷贝、is与四、基础部分的脑图总括一、内置高阶函数 map()函数 reduce()函数 filter()函数 sorted()函数 #排序 二、异常处理 Indent…

java基础巩固-宇宙第一AiYWM:为了维持生计,测试篇预热【单元测试、性能测试、灰度发布与回滚】~整起

单元测试【就像买保险&#xff0c;希望自己不要用上】是重构的保护网&#xff1a;单元测试可以为重构提供信心&#xff0c;降低重构的成本。我们要像重视生产代码那样&#xff0c;重视单元测试【元测试&#xff08;Unit Testing&#xff09;是针对程序模块&#xff08;软件设计…

协同过滤CF

算法提出 如果让推荐系统领域的从业者选出业界影响力最大、应用最广泛的模型&#xff0c;那么笔者认为90%的从业者会首选协同过滤。1992年, Xerox的研究中心开发了一种基于协同过滤的邮件筛选系统&#xff0c;用以过滤一些用户不感兴趣的无用邮件。2003 年&#xff0c;Amazon …

MySQL数据表的基础知识

目录 一、增 二、查 a、全列查询 b、指定列查询 c、查询字段为表达式 d、别名查询 e、对查询结果进行去重 f、排序 ​g、条件查询 三、改 四、删 以下操作均以student表为基础&#xff1a; 一、增 insert into 表名 values(...); 例如&#xff1a;新增张三同学的…

举个栗子!Tableau 技巧(247):用震波图(Seismogram)查看数据变化

震波图&#xff08;Seismogram&#xff09;是一种像地震波或声波的图表&#xff0c;通常用于表达数据的变化。乍一看&#xff0c;它有点像 蝴蝶图&#xff08;旋风图&#xff09;&#xff0c;数据都分布在轴的零点两侧&#xff0c;但其实两者完全不同。 如下震波图&#xff0c…

Stm32旧版库函数6——ov2640 串口显示图像 串口中断 使用旧版库 模拟IIC

/******************************************************************************* // // 使用单片机STM32F100C8T6 8 // 晶振&#xff1a;8.00M // 编译环境 Keil uVision4 // 在3.3V的供电环境下&#xff0c;就能运行 // 波特率 115200 // 使用&#xff1a;STM32F100C…

SpringCloud Config 分布式配置中心

分步式系统面临配置问题&#xff1a; 微服务意味着要将单体应用中的业务拆分成一个个子服务&#xff0c;每个服务的粒度相对较小&#xff0c;因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行&#xff0c;所以一套集中式的、动态的配置管理设施是必不…

浅谈电气火灾监控系统在煤矿高层公寓中的应用分析

摘要&#xff1a; 煤矿高层公寓做为人员高度密集场所&#xff0c;使用的电器种类繁多&#xff0c;一旦发生电气火灾事故&#xff0c; 其严重性和危害性远高于其它场所。文章通过对煤矿公寓电气线路火灾主要形式的分析&#xff0c;对电气火灾监 控系统在煤矿公寓电气火灾预防及…