问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

springboot异步调用?

发布网友 发布时间:2024-09-26 15:28

我来回答

1个回答

热心网友 时间:2024-12-02 15:14

SpringBoot之@Async异步调用

利用SpringInitializer创建一个gradle项目spring-boot-async-task,创建时添加相关依赖。

在SpringBoot入口类上配置@EnableAsync注解开启异步处理。

创建任务抽象类AbstractTask,并分别配置三个任务方法doTaskOne(),doTaskTwo(),doTaskThree()。

下面通过一个简单示例来直观的理解什么是同步调用:

定义Task类,继承AbstractTask,三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内)。

在单元测试用例中,注入Task对象,并在测试用例中执行doTaskOne(),doTaskTwo(),doTaskThree()三个方法。

执行单元测试,可以看到类似如下输出:

任务一、任务二、任务三顺序的执行完了,换言之doTaskOne(),doTaskTwo(),doTaskThree()三个方法顺序的执行完成。

上述的可以看到执行时间比较长,若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以考虑通过异步调用的方式来并发执行。

创建AsyncTask类,分别在方法上配置@Async注解,将原来的同步方法变为异步方法。

在单元测试用例中,注入AsyncTask对象,并在测试用例中执行doTaskOne(),doTaskTwo(),doTaskThree()三个方法。

执行单元测试,可以看到类似如下输出:

如果反复执行单元测试,可能会遇到各种不同的结果,比如:

原因是目前doTaskOne(),doTaskTwo(),doTaskThree()这三个方法已经异步执行了。主程序在异步调用之后,主程序并不会理会这三个函数是否执行完成了,由于没有其他需要执行的内容,所以程序就自动结束了,导致了不完整或是没有输出任务相关内容的情况。

根据业务需求,可以将暂时不需要立即获得处理的方法设置为@Async.

比如用户在前端点击完成了登录操作,这时候根据业务要求需要在登录成功之后进行埋点的处理.

其实埋点成功与否都不影响用户操作,这时候就可以将埋点方法设置为@Async.

个人认为此类任务通常有三个特征:

为了让doTaskOne(),doTaskTwo(),doTaskThree()能正常结束,假设我们需要统计一下三个任务并发执行共耗时多少,这就需要等到上述三个函数都完成动用之后记录时间,并计算结果。

那么我们如何判断上述三个异步调用是否已经执行完成呢?我们需要使用FutureT来返回异步调用的结果。

在单元测试用例中,注入AsyncCallBackTask对象,并在测试用例中执行doTaskOneCallback(),doTaskTwoCallback(),doTaskThreeCallback()三个方法。循环调用Future的isDone()方法等待三个并发任务执行完成,记录最终执行时间。

在测试用例一开始记录开始时间;在调用三个异步函数的时候,返回Future类型的结果对象;在调用完三个异步函数之后,开启一个循环,根据返回的Future对象来判断三个异步函数是否都结束了。若都结束,就结束循环;若没有都结束,就等1秒后再判断。跳出循环之后,根据结束时间-开始时间,计算出三个任务并发执行的总耗时。

执行一下上述的单元测试,可以看到如下结果:

可以看到,通过异步调用,让任务一、任务二、任务三并发执行,有效的减少了程序的运行总时间。

在上述操作中,创建一个线程池配置类TaskConfiguration,并配置一个任务线程池对象taskExecutor。

上面我们通过使用ThreadPoolTaskExecutor创建了一个线程池,同时设置了以下这些参数:

创建AsyncExecutorTask类,三个任务的配置和AsyncTask一样,不同的是@Async注解需要指定前面配置的线程池的名称taskExecutor。

在单元测试用例中,注入AsyncExecutorTask对象,并在测试用例中执行doTaskOne(),doTaskTwo(),doTaskThree()三个方法。

执行一下上述的单元测试,可以看到如下结果:

执行上面的单元测试,观察到任务线程池的线程池名的前缀被打印,说明线程池成功执行异步任务!

解决方案如下,重新设置线程池配置对象,新增线程池setWaitForTasksToCompleteOnShutdown()和setAwaitTerminationSeconds()配置:

SpringBoot-异步任务

有时候,前端可能提交了一个耗时任务,如果后端接收到请求后,直接执行该耗时任务,那么前端需要等待很久一段时间才能接受到响应。如果该耗时任务是通过浏览器直接进行请求,那么浏览器页面会一直处于转圈等待状态。一个简单的例子如下所示:

当我们在浏览器请求localhost:8080/async/页面时,可以看到浏览器一直处于转圈等待状态,这样体验十分不友好。

事实上,当后端要处理一个耗时任务时,通常都会将耗时任务提交到一个异步任务中进行执行,此时前端提交耗时任务后,就可直接返回,进行其他操作。

在Java中,开启异步任务最常用的方式就是开辟线程执行异步任务,如下所示:

这时浏览器请求localhost:8080/async/,就可以很快得到响应,并且耗时任务会在后台得到执行。

一般来说,前端不会关注耗时任务结果,因此前端只需负责提交该任务给到后端即可。但是如果前端需要获取耗时任务结果,则可通过Future等方式将结果返回,详细内容请参考后文。

事实上,在SpringBoot中,我们不需要手动创建线程异步执行耗时任务,因为Spring框架已提供了相关异步任务执行解决方案,本文主要介绍下在SpringBoot中执行异步任务的相关内容。

Spring3.0时提供了一个@Async注解,该注解用于标记要进行异步执行的方法,当在其他线程调用被@Async注解的方法时,就会开启一个线程执行该方法。

注:@Async注解通常用在方法上,但是也可以用作类型上,当类被@Async注解时,表示该类中所有的方法都是异步执行的。

在SpringBoot中,如果要执行一个异步任务,只需进行如下两步操作:

被@Async注解的异步任务方法存在相关*:

默认情况下,Spring会自动搜索相关线程池定义:要么是一个唯一TaskExecutorBean实例,要么是一个名称为taskExecutor的ExecutorBean实例。如果这两个Bean实例都不存在,就会使用SimpleAsyncTaskExecutor来异步执行被@Async注解的方法。

综上,可以知道,默认情况下,Spring使用的Executor是SimpleAsyncTaskExecutor,SimpleAsyncTaskExecutor每次调用都会创建一个新的线程,不会重用之前的线程。很多时候,这种实现方式不符合我们的业务场景,因此通常我们都会自定义一个Executor来替换SimpleAsyncTaskExecutor。

对于自定义Executor(自定义线程池),可以分为如下两个层级:

前文介绍过,对于被@Async注解的异步方法,只能返回void或者Future类型。对于返回Future类型数据,如果异步任务方法抛出异常,则很容易进行处理,因为Future.get()会重新抛出该异常,我们只需对其进行捕获即可。但是对于返回void的异步任务方法,异常不会传播到被调用者线程,因此我们需要自定义一个额外的异步任务异常处理器,捕获异步任务方法抛出的异常。

自定义异步任务异常处理器的步骤如下所示:

SpringBoot异步任务--@EnableAsync详解

@EnableAsync注解启用了Spring异步方法执行功能,在SpringFrameworkAPI中有详细介绍。

@EnableAsync默认启动流程:

1搜索关联的线程池定义:上下文中唯一的TaskExecutor实例,或一个名为taskExecutor的java.util.concurrent.Executor实例;

2如果以上都没找到,则会使用SimpleAsyncTaskExecutor处理异步方法调用。

注意:具有void返回类型的带注释方法不能将任何异常发送回调用者,默认情况下此类未捕获异常只会被记录日志。

定制@EnableAsync启动行为:

1实现AsyncConfigurer接口

2实现getAsyncExecutor()方法自定义java.util.concurrent.Executor

3实现getAsyncUncaughtExceptionHandler()方法自定义AsyncUncaughtExceptionHandler

示例:修改AsyncConfig配置类实现

SpringBoot微服务异步调用@EnableAsync@Async

第一步:在Application启动类上面加上@EnableAsync注解

第二步:定义[线程池]

第三步:在异步方法上添加@Async

第四步:测试

输出结果:

时间testA:2

开始testB

开始testA

完成testA

完成testB

任务testA,当前线程:async-thread-pool-1

时间testB:3002

异步方法@Async注解失效情况:

(1)在@SpringBootApplication启动类没有添加注解@EnableAsync

(2)调用方法和异步方法写在同一个类,需要在不同的类才能有效。

(2)调用的是静态(static)方法

(3)调用(private)私有化方法

个别失效报错情况:

报错一:提示需要在@EnableAsync上设置proxyTargetClass=true来强制使用基于cglib的代理。注解上加上即可。

Springboot使用@Async开启异步调用

大家都知道,java是同步顺序执行。当需要异步执行时,需要新创建一个线程完成。

1.使用常规的方法显示异步调用

第一步新建ThreadTest.java实现Runnable接口

第二步新建测试执行

当然,除了这种显式newThread对象,我们通过线程池获取线程名称,这里不做演示。我们熟悉的spring在spring3中提供了@Async注解,来方便开发者优雅的使用异步调用。

2.使用springboot@Async注解,优雅的实现异步调用

第一步开启异步调用注解。

第二步定义线程池

第三步创建service测试类TestService.java

第四步新建Service实现类,TestServiceImpl.java

第五步测试执行,执行结果

SpringBoot使用@Async优雅的异步调用就暂时记录到这里,欢迎评论区一起讨论学习。

一图看懂SpringBoot异步框架

在SpringBoot的日常开发中,一般都是同步调用的。但经常有特殊业务需要做异步来处理,例如:注册新用户,送100个积分,或下单成功,发送push消息等等。

就拿注册新用户为什么要异步处理?

在SpringBoot中使用异步调用是很简单的,只需要使用@Async注解即可实现方法的异步调用。

采用@EnableAsync来开启异步任务支持,另外需要加入@Configuration来把当前类加入springIOC容器中。

增加一个service类,用来做积分处理。

@Async添加在方法上,代表该方法为异步处理。

@Async注解,在默认情况下用的是SimpleAsyncTaskExecutor线程池,该线程池不是真正意义上的线程池,因为线程不重用,每次调用都会新建一条线程。

可以通过控制台日志输出查看,每次打印的线程名都是[task-1]、[task-2]、[task-3]、[task-4].....递增的。

@Async注解异步框架提供多种线程

SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。

SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方。

ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类。

ThreadPoolTaskScheler:可以使用cron表达式。

ThreadPoolTaskExecutor:最常使用,推荐。其实质是对java.util.concurrent.ThreadPoolExecutor的包装。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
谁能给个单机版的风云之雄霸天下啊?? 求风云雄霸天下PC单机游戏WIN7版 雄霸天下任务指南 开心网001老房子卖了以后家具还有吗? 为什么001开心网买房子组件删除仓库里的东西都没了 请教一下,开心001的开心庄园里面的建材有好多富余的的 除了5元一个卖... 开心网001小号怎么给大号送房子? 开心网001多少级能送别人房子?多少级能接受别人给的房子? 开心网001果实或家具能送人吗 开心网(kaixin001)怎么买外地房子? 12306退票需要到窗口吗? 华硕K52XI48JT-SL原来是希捷接口SATA2,500G硬盘,可以更换为希捷接口SATA... 低调的近义词 我在淘宝买了一双鞋子,20多天了,给差评,现在让我改了差评,返我5元,可 ... 在淘宝里买了一双鞋穿了一下就坏了,但已给了好评怎么办 三个连续的奇数后两个数与前两个数的的积之差是252,三个数中最小的数... 有三个连续的奇数乘积为5()()()3,那么求这三个连续的奇数为哪三个... 我在淘宝买了鞋子 收到很不满意, 然后给了差评、现在店家人肉我了 在淘宝上买到假鞋子被卖家威胁,大家有相同经历吗? 三个连续奇数相乘的积的个位数字最小是几 已知三个连续数的和是75,那么着三个奇数中最小的数十? 我五月份的时候在网上买了双鞋子 鞋子不好 给了差评 卖家一直让我删评论... 迈威作为国产车,品控做的怎么样? 我要订一张打折飞机票,上海到成都 从上海到成都的机票多少钱 最好是打折的 上海到成都打折机票请问上海到成都12号或者13号现在能买到打折机票吗再... 哪里可以订上海飞成都的便宜机票? 小米有红外功能吗? 上海到成都机票价格 7月要从上海飞到成都,怎样才能买到便宜机票? 华硕K52XI48JU-SL(2G/500GB)这笔记本可以玩穿越火线吗?会会不会卡机... 华硕K52EI46JE-SL怎么样,现在的价格具体多少合适?性能怎么样,用过的... 联想B505和Y470哪个用起来比较合算 K42EI48JP-SL(4GB/500GB)跟A40EI48JP-SL 哪个好 麻烦大家说说 区别在哪... springbean初始化和实例化? ...不玩游戏。现在想请大家推荐一款华硕的笔记本,14寸,4000-6000都可 ... C#.NET禁止一个程序启动多个实例 什么办法可以替代32号汽轮机油? apk文件是在哪个文件夹里的呢? 黄童白叟代表什么生肖 黄童白叟什么生肖 如果安装微信, apk安装包会到哪里去? 四大银行哪个银行安全 中国四大银行哪家最安全可靠 《阿诗玛》故事 为什么文件夹打不开? 铁人精神的内涵是什么王进喜铁人精神的内涵是什么 周杰伦最新优乐美广告背景音乐,不是蒲公英的约定,也不是最长的电影,20... 和周杰伦一起拍优乐美广告的是谁 有他的详细资料吗 周杰伦优乐美奶茶新版广告(海边别墅篇) 广告里的女的叫什么名字 谢谢...