SpringBoot - Async异步处理

目录

一、定义

1、同步调用

2、异步调用

二、示例

1、同步调用

执行类:

测试用例: 

运行结果:

2、异步调用

(1)普通调用

执行类:

测试用例:

运行结果:

(2)异步回调

执行类:

测试用例:

执行逻辑:


一、定义

1、同步调用

  • 定义同步调用是一种按照顺序依次执行任务的方式。在程序中,当一个函数或方法调用另一个函数或方法时,调用者会暂停自身的执行,等待被调用者执行完毕并返回结果后,调用者才会继续执行后续的操作。
  • 就好像一个人在排队等待服务,必须等到前面的人完成服务后,自己才能接受服务并继续下一步行动。

2、异步调用

  • 定义异步调用是一种不阻塞调用者执行的调用方式。当一个函数或方法被异步调用时,调用者不会等待被调用者执行完毕,而是继续执行自己后续的操作。被调用者在后台独立运行,当它完成任务后,会通过某种方式(如回调函数、事件通知等)将结果返回给调用者。
  • 这就好比一个人在餐厅点了菜后,不需要一直坐在那里等待上菜,而是可以去做其他事情,等菜做好了,服务员会通知他。

二、示例

1、同步调用

执行类:

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

package com.example.springbootasync.demos.web;import org.springframework.stereotype.Component;import java.util.Random;/*** @Author: * @CreateTime: 2024-11-15* @Description: 同步任务执行类*/
@Component
public class SynchronizationTask {public static Random random = new Random();public void taskOne() throws Exception {System.out.println("任务一开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务一完成耗时:" + (end - start) + "毫秒");}public void taskTwo() throws Exception {System.out.println("任务二开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务二完成耗时:" + (end - start) + "毫秒");}public void taskThree() throws Exception {System.out.println("任务三开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务三完成耗时:" + (end - start) + "毫秒");}}
 测试用例: 

          在单元测试用例中,注入SynchronizationTask对象,并在测试用例中执行taskOne、taskTwo、taskThree三个函数。

package com.example.springbootasync;import com.example.springbootasync.demos.web.SynchronizationTask;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class SpringBootAsyncApplicationTests {@Autowiredprivate SynchronizationTask sTask;@Testvoid synchronizationTask() throws Exception {sTask.taskOne();sTask.taskTwo();sTask.taskThree();}}

执行单元测试

运行结果:

任务一开始执行......
任务一完成耗时:2649毫秒
任务二开始执行......
任务二完成耗时:7083毫秒
任务三开始执行......
任务三完成耗时:5752毫秒

        可以看出三个任务是按照顺序执行的,这就是同步调用,一个任务执行完成才能执行下一个任务。

2、异步调用

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

       为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync
public class SpringBootAsyncApplication {public static void main(String[] args) {SpringApplication.run(SpringBootAsyncApplication.class, args);}}

(1)普通调用

        在Spring Boot中,我们只需要通过使用 @Async注解 就能简单的将原来的 同步函数变为异步函数,将SynchronizationTask类进行改造,如下:

执行类:
package com.example.springbootasync.demos.web;import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;import java.util.Random;
import java.util.concurrent.Future;/*** @Author: wxzhanglinsen* @CreateTime: 2024-11-15* @Description: 异步任务执行类*/
@Component
public class AsyncTask {public static Random random = new Random();@Asyncpublic void taskOne() throws Exception {//同上}@Asyncpublic void taskTwo() throws Exception {//同上}@Asyncpublic void taskThree() throws Exception {//同上}}
测试用例:
package com.example.springbootasync;import com.example.springbootasync.demos.web.AsyncTask;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class SpringBootAsyncApplicationTests {@Autowiredprivate AsyncTask aTask;@Testvoid asyncTask() throws Exception {aTask.taskOne();aTask.taskTwo();aTask.taskThree();}}
运行结果:

任务二开始执行......
任务三开始执行......
任务一开始执行......

任务二开始执行......
任务一开始执行......
任务三开始执行......

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

  • 没有任何任务相关的输出

  • 有部分任务相关的输出

  • 乱序的任务相关的输出

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

注意:@Async所修饰的函数不要定义为static类型,这样异步调用不会生效。

(2)异步回调

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

        那么我们如何判断上述三个异步调用是否已经执行完成呢?我们需要使用Future来返回异步调用的结果,就像如下方式改造AsyncTask类中的函数:

 执行类:
package com.example.springbootasync.demos.web;import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;import java.util.Random;
import java.util.concurrent.Future;/*** @Author: wxzhanglinsen* @CreateTime: 2024-11-15* @Description: 异步任务执行类*/
@Component
public class AsyncTask {public static Random random = new Random();@Asyncpublic Future<String> taskOne() throws Exception {System.out.println("任务一开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务一完成耗时:" + (end - start) + "毫秒");return new AsyncResult<>("任务一完成");}@Asyncpublic Future<String> taskTwo() throws Exception {System.out.println("任务二开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务二完成耗时:" + (end - start) + "毫秒");return new AsyncResult<>("任务二完成");}@Asyncpublic Future<String> taskThree() throws Exception {System.out.println("任务三开始执行......");long start = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long end = System.currentTimeMillis();System.out.println("任务三完成耗时:" + (end - start) + "毫秒");return new AsyncResult<>("任务三完成");}
}
测试用例:
package com.example.springbootasync;import com.example.springbootasync.demos.web.AsyncTask;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.concurrent.Future;@SpringBootTest
class SpringBootAsyncApplicationTests {@Autowiredprivate AsyncTask aTask;@Testvoid asyncTask() throws Exception {long start = System.currentTimeMillis();Future<String> task1 = aTask.taskOne();Future<String> task2 = aTask.taskTwo();Future<String> task3 = aTask.taskThree();while(true) {if(task1.isDone() && task2.isDone() && task3.isDone()) {// 三个任务都调用完成,退出循环等待break;}//停隔1s再进行扫描,扫描任务是否都已经完成Thread.sleep(1000);}long end = System.currentTimeMillis();System.out.println("任务全部完成,总耗时:" + (end - start) + "毫秒");}
}
执行逻辑:
  • 在测试用例一开始记录开始时间

  • 在调用三个异步函数的时候,返回Future类型的结果对象

  • 在调用完三个异步函数之后,开启一个循环,根据返回的Future对象来判断三个异步函数是否都结束了。若都结束,就结束循环;若没有都结束,就等1秒后再判断。

跳出循环之后,根据结束时间 - 开始时间,计算出三个任务并发执行的总耗时。

运行结果:

任务一开始执行......
任务二开始执行......
任务三开始执行......
任务一完成耗时:188毫秒
任务二完成耗时:4828毫秒
任务三完成耗时:9208毫秒
任务全部完成,总耗时:10014毫秒

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络HTTP——针对实习面试

目录 计算机网络HTTP什么是HTTP&#xff1f;HTTP和HTTPS有什么区别&#xff1f;分别说明HTTP/1.0、HTTP/2.0、HTTP/3.0请说明访问网页的全过程请说明HTTP常见的状态码Cookie和Session有什么区别&#xff1f;HTTP请求方式有哪些&#xff1f;请解释GET和POST的区别&#xff1f;HT…

Win11 终端执行 python xxx.py 没反应

在 Win11 上写了一段 Python 代码来分析日志文件&#xff0c; 发现执行没反应。是在 VSCode 里的终端中执行的 python log_stats.py, 是 PowerShell&#xff1b; 也尝试了 cmd&#xff0c; 情况一样。 一开始怀疑代码写错&#xff0c;直到故意在代码里加打印&#xff0c;发现没…

自由学习记录(22)

最后再总结一下吧 虽然过程里很多细节也许我没有去管&#xff0c;毕竟现在就已经存在更好的解决方案了 但大致思想是了解了 A星是一种网格上的遍历方式&#xff0c;为了找到一个目标点和起点之间的要经过的最短节点组 里面更像是动态规划 每一次的遍历&#xff0c;都是当前…

如何保证MySQL与Redis缓存的数据一致性?

文章目录 一、引言二、场景来源三、高并发解决方案1. 先更新缓存&#xff0c;再更新数据库2. 先更新数据库&#xff0c;再更新缓存3. 先删除缓存&#xff0c;再更新数据库4. 先更新数据库&#xff0c;再删除缓存小结 四、拓展方案1. 分布式锁与分布式事务2. 消息队列3. 监听bin…

java-Day06 内部类 Lambda表达式 API

内部类 内部类:就是在一个类中定义一个类 格式例: public class Outer { public class Inner { } } 内部类分类 1.成员内部类(了解) 创建成员内部类 外部类.内部类 对象名new外部类().new内部类() 2.静态内部类(了解) 3.局部内部类(了解) 4.匿名内部类…

【3D Slicer】的小白入门使用指南八

3D Slicer DMRI(Diffusion MRI)-扩散磁共振认识和使用 0、简介 大脑解剖 ● 白质约占大脑的 45% ● 有髓神经纤维(大约10微米轴突直径) 白质探索 朱尔斯约瑟夫德杰林(Jules Joseph Dejerine,《神经中心解剖学》(巴黎,1890-1901):基于髓磷脂染色标本的神经解剖图谱)…

Spring Boot框架:构建可扩展的网上商城

4 系统设计 网上商城系统的设计方案比如功能框架的设计&#xff0c;比如数据库的设计的好坏也就决定了该系统在开发层面是否高效&#xff0c;以及在系统维护层面是否容易维护和升级&#xff0c;因为在系统实现阶段是需要考虑用户的所有需求&#xff0c;要是在设计阶段没有经过全…

【Pikachu】任意文件上传实战

将过去和羁绊全部丢弃&#xff0c;不要吝惜那为了梦想流下的泪水。 1.不安全的文件上传漏洞概述 不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见&#xff0c;比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后&#xff0c;后台会对上传的…

vue3:computed

vue3:computed 扫码或者点击文字后台提问 computed 支持选项式写法 和 函数式写法 1.选项式写法 支持一个对象传入get函数以及set函数自定义操作 2.函数式写法 只能支持一个getter函数不允许修改值的 基础示例 <template><div><div>姓&#xff1a;<i…

Python调用API翻译Excel中的英语句子并回填数据

一、问题描述 最近遇到一个把Excel表中两列单元格中的文本读取&#xff0c;然后翻译&#xff0c;再重新回填到单元格中的案例。大约有700多行&#xff0c;1400多个句子&#xff0c;一个个手动复制粘贴要花费不少时间&#xff0c;而且极易出错。这时&#xff0c;我们就可以请出…

NFS-Ganesha 核心架构解读

NFSv4 简要概述 NFS 这个协议( NFSv2 )最初由 Sun Microsystems 在 1984 年设计提出&#xff0c;由于存在一些不足&#xff0c;因此在随后由几家公司联合推出了 NFSv3。到了 NFSv4 时&#xff0c;开发完全由 IETF 主导&#xff0c;设计目标是&#xff1a; 提高互联下的 NFS 访…

直流保护电路设计及保护器件参数说明和选型

在工控产品设计中时常会涉及到电源保护的电路设计的问题&#xff0c;在深圳瑞隆源电子给出的参考电路来切入主题&#xff0c;对气体放电管、压敏电阻和TVS这三类保护器件的参数及选型进行详细说明&#xff0c;以达到深刻理解的目的。 图1 直流保护电路 举例说明&#xff0c;若…

VBA学习笔记:点击单元格显示指定的列

应用场景&#xff1a; 表格中列数较多&#xff0c;特定条件下隐藏一些无关的列&#xff0c;只保留相关的列&#xff0c;使表格更加清晰。 示例&#xff1a;原表格如下 点击一年级&#xff0c;只显示一年级相关的科目&#xff1a; 点击二年级&#xff0c;只显示二年级相关的科…

一种时间戳对齐的方法(离线)

这段代码的主要功能是: 读取指定目录下的 pcd 文件和 jpg 文件。对于每个 pcd 文件,在 jpg 目录中找到时间戳最接近的 jpg 文件。将找到的 jpg 文件复制到对应的输出目录,实现时间戳对齐。 这种时间戳对齐的操作在多传感器数据融合中非常常见,它确保了不同传感器采集的数据在时…

『VUE』27. 透传属性与inheritAttrs(详细图文注释)

目录 什么是透传属性&#xff08;Forwarding Attributes&#xff09;使用条件唯一根节点禁用透传属性继承总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 什么是透传属性&#xff08;Forwarding Attributes&#xff09; 在 V…

【代码大模型】Is Your Code Generated by ChatGPT Really Correct?论文阅读

Is Your Code Generated by ChatGPT Really Correct? Rigorous Evaluation of Large Language Models for Code Generation key word: evaluation framework, LLM-synthesized code, benchmark 论文&#xff1a;https://arxiv.org/pdf/2305.01210.pdf 代码&#xff1a;https:…

AdaBoost 二分类问题

代码功能 生成数据集&#xff1a; 使用 make_classification 创建一个模拟分类问题的数据集。 数据集包含 10 个特征&#xff0c;其中 5 个是有用特征&#xff0c;2 个是冗余特征。 数据集划分&#xff1a; 将数据分为训练集&#xff08;70%&#xff09;和测试集&#xff08;3…

maven的optional选项说明以及具体应用

写在前面 本文看下maven的optional选项的作用和用法。 1&#xff1a;什么作用 考虑这样的场景&#xff0c;A依赖B&#xff0c;B依赖C&#xff0c;正常的按照依赖的传递性&#xff0c;A也会间接的依赖C&#xff0c;但是在一些特定的场景中项目A只希望依赖B&#xff0c;而不依…

QSS 设置bug

问题描述&#xff1a; 在QWidget上add 一个QLabel&#xff0c;但是死活不生效 原因&#xff1a; c 主程序如下&#xff1a; QWidget* LOGO new QWidget(logo_wnd);LOGO->setFixedSize(logo_width, 41);LOGO->setObjectName("TittltLogo");QVBoxLayout* tit…

论文阅读 - Causally Regularized Learning with Agnostic Data Selection

代码链接&#xff1a; GitHub - HMTTT/CRLR: CRLR尝试实现 https://arxiv.org/pdf/1708.06656v2 目录 摘要 INTRODUCTION 2 RELATED WORK 3 CAUSALLY REGULARIZED LOGISTIC REGRESSION 3.1 Problem Formulation 3.2 Confounder Balancing 3.3 Causally Regularized Lo…