浅析Spring中Async注解底层异步线程池原理
一、前言
开发中我们经常会用到异步方法调用,具体到代码层面,异步方法调用的实现方式有很多种,比如最原始的通过实现Runnable接口或者继承Thread类创建异步线程,然后启动异步线程;再如,可以直接用java.util.concurrent包提供的线程池相关API实现异步方法调用。
如果说可以用一行代码快速实现异步方法调用,那是不是比上面方法香很多。
Spring提供了Async注解,就可以帮助我们一行代码搞定异步方法调用。Async注解用起来是很爽,但是如果不对其底层实现做深入研究,难免有时候也会心生疑虑,甚至会因使用不当,遇见一些让人摸不着头脑的问题。
本文首先将对Async注解做简单介绍,然后和大家分享一个我们项目中因Async注解使用不当的线上问题,接着再深扒Spring源码,对Async注解底层异步线程池的实现原理一探究竟。
二、Async注解简介
Async注解定义源码
从源码可以看出@Async注解定义很简单,只需要关注两点:
-
Target({ElementType.TYPE, ElementType.METHOD})标志Async注解可以作用在方法和类上,作用在类上时,类的所有方法可以实现异步调用。
-
String value( ) default ""是唯一字段属性,用来指定异步线程池,且该字段有缺省值。
Async注解异步调用实现原理概述
在Spring框架中,Async注解的实现是通过AOP来实现的。具体来说,Async注解是由AsyncAnnotationAdvisor这个切面类来实现的。
AsyncAnnotationAdvisor类是Spring框架中用于处理Async注解的切面,它会在被Async注解标识的方法被调用时,创建一个异步代理对象来执行方法。这个异步代理对象会在一个新的线程中调用被@Async注解标识的方法,从而实现方法的异步执行。
在AsyncAnnotationAdvisor中,会使用AsyncExecutionInterceptor来处理Async注解。AsyncExecutionInterceptor是实现了MethodInterceptor接口的类,用于拦截被Async注解标识的方法的调用,并在一个新的线程中执行这个方法。
通过AOP的方式实现Async注解的异步执行,Spring框架可以在方法调用时动态地创建代理对象来实现异步执行,而不需要在业务代码中显式地创建新线程。
总的来说,Async注解的实现是通过AOP机制来实现的,具体的切面类是AsyncAnnotationAdvisor,它利用AsyncExecutionInterceptor来处理被Async注解标识的方法的调用,实现方法的异步执行。
三、Async注解底层异步线程池原理探究
获取Async注解线程池主流程解析
进入到Spring源码Async注解AOP切面实现部分,我们重点剖析异步调用实现中线程池是怎么处理的。下图是org.springframework.aop.interceptor.AsyncExecutionInterceptor#invoke方法的实现,可以看出是调用determineAsyncExecutor方法获取异步线程池。
AsyncExecutionInterceptor#invoke
下图是determineAsyncExecutor方法实现:
上方的图为AsyncExecutionInterceptor#determineAsyncExecutor,下方的图为AsyncExecutionAspectSupport#getExecutorQualifier
从代码实现中可以看到determineAsyncExecutor获取线程池的大致流程:
determineAsyncExecutor获取线程池流程
如果在使用Async注解时指定了自定义线程池比较好理解,如果使用Async注解时没有指定自定义线程池,Spring是怎么处理默认线程池呢?继续深入源码看看Spring提供的默认线程池的实现。
Spring是怎么为Async注解提供默认线程池的
Async注解默认线程池有下面两个方法实现:
-
org.springframework.aop.interceptor.AsyncExecutionInterceptor#getDefaultExecutor
-
org.springframework.aop.interceptor.AsyncExecutionAspectSupport#getDefaultExecutor
AsyncExecutionInterceptor#getDefaultExecutor
可以看出AsyncExecutionInterceptor#getDefaultExecutor方法比较简单:先尝试调用父类AsyncExecutionAspectSupport#getDefaultExecutor方法获取线程池,如果父类方法获取不到线程池再用创建SimpleAsyncTaskExecutor对象作为Async的线程池返回。
AsyncExecutionAspectSupport#getDefaultExecutor
再来看父类AsyncExecutionAspectSupport#getDefaultExecutor方法的实现,可以看到Spring根据类型从Spring容器中获取TaskExecutor类的实例,先记住这个关键点。
我们知道,Spring根据类型获取实例时,如果spring容器中有且只有一个指定类型的实例对象,会直接返回,否则的话,会抛出NoUniqueBeanDefinitionException异常或者NoSuchBeanDefinitionException异常。
但是,对于Executor类型,Spring容器却“网开一面”,有一个特殊处理:当从Spring容器中获取Executor实例对象时,如果满足@ConditionalOnMissingBean(Executor.class)条件,Spring容器会自动装载一个ThreadPoolTaskExecutor实例对象,而ThreadPoolTaskExecutor是TaskExecutor的实现类。
上方的图为TaskExecutionAutoConfiguration,下方的图为TaskExecutionProperties
从TaskExecutionProperties和TaskExecutionAutoConfiguration两个配置类我们看到Spring自动装载的ThreadPoolTaskExecutor线程池对象的参数:核心线程数=8;最大线程数=Integer.MAX_VALUE;队列大小=Integer.MAX_VALUE。
四、总结
现在Async注解线程池源码已经看的差不多了,下面这张图是Spring处理Async异步线程池的流程:
Async异步线程池获取流程
归纳一下:如果在使用Async注解时没有指定自定义的线程池会出现以下几种情况:
-
当Spring容器中有且仅有一个TaskExecutor实例时,Spring会用这个线程池来处理Async注解的异步任务,这可能会踩坑,如果这个TaskExecutor实例是第三方jar引入的,可能会出现很诡异的问题。
-
Spring创建一个核心线程数=8、最大线程数=Integer.MAX_VALUE、队列大小=Integer.MAX_VALUE的线程池来处理Async注解的异步任务,这时候也可能会踩坑,由于线程池参数设置不合理,核心线程数=8,队列大小过大,如果有大批量并发任务,可能会出现OOM。
-
Spring创建SimpleAsyncTaskExecutor实例来处理Async注解的异步任务,SimpleAsyncTaskExecutor不是一个好的线程池实现类,SimpleAsyncTaskExecutor根据需要在当前线程或者新线程中执行异步任务。如果当前线程已经有空闲线程可用,任务将在当前线程中执行,否则将创建一个新线程来执行任务。由于这个线程池没有线程管理的能力,每次提交任务都实时创建新城,所以如果任务量大,会导致性能下降。
*文/Simon
本文属得物技术原创,更多精彩文章请看:得物技术
未经得物技术许可严禁转载,否则依法追究法律责任!
相关文章:

浅析Spring中Async注解底层异步线程池原理
一、前言 开发中我们经常会用到异步方法调用,具体到代码层面,异步方法调用的实现方式有很多种,比如最原始的通过实现Runnable接口或者继承Thread类创建异步线程,然后启动异步线程;再如,可以直接用java.uti…...

sqli-labs 靶场 less-7 第七关详解:OUTFILE注入与配置
SQLi-Labs是一个用于学习和练习SQL注入漏洞的开源应用程序。通过它,我们可以学习如何识别和利用不同类型的SQL注入漏洞,并了解如何修复和防范这些漏洞。Less 7 SQLI DUMB SERIES-7判断注入点 进入页面中,并输入数据查看结果。 发现空数据提…...
AIGC新秀亮相,哪款大模型产品最得你心?
AIGC新秀亮相,哪款大模型产品最得你心? 近日,腾讯元宝APP的正式上线,为国内大模型AIGC产品市场增添了一名新成员。 这些所谓的“全能”大模型产品,凭借其强大的生成能力和广泛的应用场景,正逐渐改变我们的…...
RabbitMQ消息的可靠传输和防止消息丢失
在Spring Cloud项目中,为了确保RabbitMQ消息的可靠传输和防止消息丢失,需要考虑以下几个方面: 消息持久化:确保消息在RabbitMQ中持久化。队列持久化:确保队列是持久化的。发布确认:使用发布确认机制确保消…...

.net8系列-图文并茂手把手教你使用Nlog记录.net日志
Nlog是什么? NLog是一个为.NET平台设计的灵活且免费的日志记录库。它适用于包括.NET Framework、.NET Core和.NET Standard在内的多种.NET环境。 Nlog有什么好处或者特点? 配置灵活:NLog允许开发者通过配置文件(通常是NLog.conf…...
课时158:脚本发布_简单脚本_远程执行
2.1.3 远程执行 学习目标 这一节,我们从 基础知识、简单实践、小结 三个方面来学习 基础知识 简介 有时候,我们需要通过远程方式到另外一台主机进行脚本的执行 格式:ssh 远程主机登录用户名远程主机ip地址 "执行命令"效果 [r…...

3dmax2025能用云渲染吗?2025最新云渲染渲染100使用方法
3dmax2025还没用上云渲染?简单3步用上云渲染。 第一步,打开浏览器搜索渲染100,并进入下载客户端并安装 第二步,打开已安装的客户端进行安装,点击登录,未登录注册个账号即可(注册账号时邀请码填…...

从零开始学GeoServer源码(一)(搭建开发环境Win10+IDEA23.3.5+jdk11+geoserver2.24.x)
搭建开发环境 参考资料 0、基础环境准备0.1、idea0.2、jdk0.3、源码 1、导入工程2、配置启动环境2.1、打开新增配置面板2.2、配置工作目录2.2.1、从常用配置中选择2.2.2、直接粘贴 2.3最终效果 3、调整源码3.1、添加maven引用3.2、注释无效代码3.3、删除测试代码 4、修改运行端…...

分类模型:MATLAB判别分析
1. 判别分析简介 判别分析(Discriminant Analysis) 是一种统计方法,用于在已知分类的样本中构建分类器,并根据特征变量对未知类别的样本进行分类。常见的判别分析方法包括线性判别分析(Linear Discriminant Analysis, …...

生产 的mybatisplus 日志输入到日志文件
默认是输出到控制台.不输出到日志文件 输出到日志文件.需要修改配置 第一步. logging:config: classpath:logback-wshoto.xml第二步 mybatis-plus:configuration:cache-enabled: truedefault-executor-type: reuselog-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl第三步…...

八分钟生成一篇两万字的文章演示——《基于灰色预测的人口预测模型》
文章目录 工具使用 《基于灰色预测的人口预测模型》-全文由AI一次性生成文献综述研究方法模型开发灰色预测模型的数学构建参数估计模型验证 案例研究案例研究描述数据收集与预处理灰色预测模型的应用 文献综述研究方法模型开发灰色预测模型的数学构建参数估计模型验证 案例研究…...
golang 透明底图转白底
url : ""var s []byte// 请求线上图片s GetUrl(url)// 处理透明底图转白底img, _, err : image.Decode(bytes.NewReader(s))if err ! nil {fmt.Println("读取图片失败")}bounds : img.Bounds()dst : image.NewNRGBA(bounds)draw.Draw(dst, bounds, image.…...

【一】【网络使用小知识】使用aria2软件结合Windows PowerShell命令行快速下载文件
下载aria2软件 点击进入网址,aria2下载网址. 下载windows版本. 通过Windows PowerShell命令行使用aria2软件下载文件 通用下载文件命令行代码 aria2软件完整路径 -x 16 -s 32 -d 下载目录(文件夹) -o 文件名 下载链接路径示例,用aria2下载qq 找到aria2应用的直接地址,结合…...

报错:C1189#error: The <experimental/filesystem> header providing 解决方案
今天开发过程中,需要使用文件系统experimental/filesystem,报错C1189#error: The <experimental/filesystem> header providing ,通过以下解决方案,成功运行程序。 目录 一、打开项目下的属性 二、选择C/…...

Elixir学习笔记——速构(函数式编程基础)
在 Elixir 中,循环遍历 Enumerable 是很常见的,通常会过滤掉一些结果并将值映射到另一个列表中。 速构是此类构造的语法糖:它们将这些常见任务分组为 for 特殊形式。 例如,我们可以将一串整数映射到它们的平方值: 速构…...

开源项目大合集(热门)
人不走空 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌赋:斯是陋室,惟吾德馨 目录 🌈个人主页:人不走空 💖系列专栏:算法专题 ⏰诗词歌…...

【JVM】JVisualVM的介绍、使用和GC过程
VisualVM介绍 VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几…...

个人在家如何获取World Scientific文献的经验分享
今天有位同学求助一篇World Scientific文献,他的学校虽然有这个数据库,但订购的该数据库资源内容有限,这位同学所需的文献不在学校订购范围内所以下载不了。今天小编就分享一个在家就可获取各个数据库文献的方法。本文以这篇求助文献为例&…...
Java 收集常见面试题
set和list的区别?给定一系列字符串,从集合的set和list中查询,如何查询出相关的数据? 在Java中,Set和List都是用于存储对象的集合 Set: 不允许包含重复的元素。 没有顺序(即不保证元素的迭代顺序…...
JS 严格模式和正常模式的区别
严格模式使用"use strict"; 作用: 消除 Javascript 语法的一些不合理、不严谨之处,减少一些怪异行为;消除代码运行的一些不安全之处,保证代码运行的安全;提高编译器效率,增加运行速度;为未来新…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...