当前位置: 首页 > news >正文

【SpringBoot】20 同步调用、异步调用、异步回调

Git仓库

https://gitee.com/Lin_DH/system

介绍

同步调用:指程序在执行时,调用方需要等待函数调用返回结果后,才能继续执行下一步操作,是一种阻塞式调用。
异步调用:指程序在执行时,调用方在调用函数后立即返回,不需要等待函数调用返回结果,可以直接执行下一步操作,当函数执行完成后,会通过回调或其他方式通知调用方,得到返回结果。
回调:在调用一个函数后,需要在函数执行中或执行后,将执行结果或状态返回给调用者。

代码实现

第一步:启动类上添加 @EnableAsync 注解,开启异步功能。

@EnableAsync
@SpringBootApplication
public class SystemApplication extends SpringBootServletInitializer {}

同步调用

第二步:添加同步调用业务逻辑
注:@Async 注解不能修饰的 static 修饰的函数,该类型的函数异步调用不会生效。

package com.lm.system.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.util.Random;/*** 同步调用* @author DUHAOLIN* @date 2024/10/17*/
@Slf4j
@Component
public class SyncTask {public static Random random = new Random();public void one() throws InterruptedException {commonTask("一");}public void two() throws InterruptedException {commonTask("二");}public void three() throws InterruptedException {commonTask("三");}public void commonTask(String s) throws InterruptedException {log.info("开始执行任务" + s);long startTime = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long endTime = System.currentTimeMillis();log.info("完成任务" + s + ",耗时:" + (endTime - startTime) + "毫秒");}}

第三步:测试类添加同步调用的测试方法

SystemApplicationTests.java

@Slf4j
@SpringBootTest(classes = SystemApplication.class)
class SystemApplicationTests {@Resourceprivate SyncTask syncTask;@Testpublic void syncTest() throws InterruptedException {long startTime = System.currentTimeMillis();syncTask.one();syncTask.two();syncTask.three();long endTime = System.currentTimeMillis();log.info("任务总耗时:" + (endTime - startTime) + "毫秒");}}

异步调用

第四步:添加异步调用业务逻辑

AsyncTask.java

/*** 异步调用* @author DUHAOLIN* @date 2024/10/17*/
@Slf4j
@Component
public class AsyncTask {public static Random random = new Random();@Asyncpublic void one() throws InterruptedException {commonTask("一");}@Asyncpublic void two() throws InterruptedException {commonTask("二");}@Asyncpublic void three() throws InterruptedException {commonTask("三");}public void commonTask(String s) throws InterruptedException {log.info("开始执行任务" + s);long startTime = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long endTime = System.currentTimeMillis();log.info("完成任务" + s + ",耗时:" + (endTime - startTime) + "毫秒");}}

第五步:测试类添加异步调用的测试方法

SystemApplicationTests.java

@Resource
private AsyncTask asyncTask;@Test
public void asyncTest() throws InterruptedException {long startTime = System.currentTimeMillis();asyncTask.one();asyncTask.two();asyncTask.three();long endTime = System.currentTimeMillis();log.info("任务总耗时:" + (endTime - startTime) + "毫秒");
}

异步回调(常用)

第六步:添加异步回调业务逻辑

AsyncCallBackTask.java

package com.lm.system.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;import java.util.Random;package com.lm.system.task;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;import java.util.Random;
import java.util.concurrent.CompletableFuture;/*** 异步回调* @author DUHAOLIN* @date 2024/10/17*/
@Slf4j
@Component
public class AsyncCallBackTask {public static Random random = new Random();@Asyncpublic CompletableFuture<String> one() throws InterruptedException {log.info("开始执行任务一");long startTime = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long endTime = System.currentTimeMillis();log.info("完成任务一,耗时:" + (endTime - startTime) + "毫秒");return CompletableFuture.completedFuture("任务一执行完成");}@Asyncpublic CompletableFuture<String> two() throws InterruptedException {log.info("开始执行任务二");long startTime = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long endTime = System.currentTimeMillis();log.info("完成任务二,耗时:" + (endTime - startTime) + "毫秒");return CompletableFuture.completedFuture("任务二执行完成");}@Asyncpublic CompletableFuture<String> three() throws InterruptedException {log.info("开始执行任务三");long startTime = System.currentTimeMillis();Thread.sleep(random.nextInt(10000));long endTime = System.currentTimeMillis();log.info("完成任务三,耗时:" + (endTime - startTime) + "毫秒");return CompletableFuture.completedFuture("任务三执行完成");}}

第七步:测试类添加异步回调的测试方法

SystemApplicationTests.java

@Resourceprivate AsyncCallBackTask asyncCallBackTask;@Testpublic void asyncCallBackTaskTest() throws InterruptedException {long startTime = System.currentTimeMillis();CompletableFuture<String> one = asyncCallBackTask.one();CompletableFuture<String> two = asyncCallBackTask.two();CompletableFuture<String> three = asyncCallBackTask.three();CompletableFuture.allOf(one, two, three).join();long endTime = System.currentTimeMillis();log.info("任务总耗时:" + (endTime - startTime) + "毫秒");}

效果图

同步调用
在这里插入图片描述
异步调用
执行完异步调用,只有任务的部分相关输出,任务的执行顺序也是乱序的。
在这里插入图片描述
异步回调
在这里插入图片描述

异步任务线程池配置

介绍

当我们用异步调用或异步回调进行并发操作时,加速了任务的执行效率,但是如果只是直接简单的创建来使用,可能会碰到一些问题和风险。当接口被频繁调用,异步任务创建的数量达到一定量级,可能会导致内存溢出,此时我们就需要对创建异步任务的操作,加上线程池的相关配置。
在这里插入图片描述
queueCapacity:缓冲队列的容量,默认为INT的最大值(2的31次方-1)
maxSize:允许的最大线程数,默认为INT的最大值(2的31次方-1)

具体配置

在这里插入图片描述

application.yml

spring:task:execution:pool:core-size: 2 #线程池创建时的初始化线程数,默认为8max-size: 5 #线程池的最大线程数,默认为int最大值queue-capacity: 10 #用来缓冲执行任务的队列,默认为int最大值keep-alive: 60s #线程终止前允许保持空闲的时间,默认为60sallow-core-thread-timeout: true #是否允许核心线程超时shutdown:await-termination: false #是否等待剩余任务完成后才关闭应用await-termination-period: #等待剩余任务完成的最大时间thread-name-prefix: task- #线程名的前缀,设置好了之后可以方便我们在日志中查看处理任务所在的线程池

application.Properties

spring.task.execution.pool.core-size=2
spring.task.execution.pool.max-size=5
spring.task.execution.pool.queue-capacity=10
spring.task.execution.pool.keep-alive=60s
spring.task.execution.pool.allow-core-thread-timeout=true
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
spring.task.execution.thread-name-prefix=task-

效果图

再次执行异步回调方法,得到如下效果图。
当前配置的初始化线程数为2,最大线程数为5,缓存队列为10,只有当缓存队列满且当前线程数小于最大线程数时,才会申请新的线程来执行任务(如:缓存队列为11,初始化线程数为2,最大线程数为5)。
在这里插入图片描述

项目结构图

在这里插入图片描述

参考资料

Spring Boot 2.x基础教程:使用@Async实现异步调用【https://www.didispace.com/spring-boot-2/8-3-async-1.html】
Spring Boot 2.x基础教程:配置@Async异步任务的线程池【https://www.didispace.com/spring-boot-2/8-3-async-2.html】

http://www.lryc.cn/news/484591.html

相关文章:

  • 【Excel】数据透视表分析方法大全
  • 深度学习在边缘检测中的应用及代码分析
  • k8s 1.28.2 集群部署 docker registry 接入 MinIO 存储
  • 常用的生物医药专利查询数据库及网站(很全!)
  • 「QT」几何数据类 之 QPolygon 多边形类
  • 写给初学者的React Native 全栈开发实战班
  • 工作和学习遇到的技术问题
  • 如何解决JAVA程序通过obloader并发导数导致系统夯住的问题 | OceanBase 运维实践
  • Git零基础到入门
  • HTTP 1.0、HTTP 1.1 和 HTTP 2.0 区别
  • 解决 ElSelect 数据量大导致加载速度慢
  • 在 CentOS 系统中,您可以使用多种工具来查看网络速度和流量
  • 分布式----Ceph部署
  • 使用 PyTorch 实现 AlexNet 进行 MNIST 图像分类
  • Python爬虫项目 | 一、网易云音乐热歌榜歌曲
  • 【Linux】HTTP协议和HTTPS加密
  • Linux编辑/etc/fstab文件不当,不使用快照;进入救援模式
  • ubuntu升级postgres
  • vue2在el-dialog打开的时候使该el-dialog中的某个输入框获得焦点方法总结
  • SpringBoot(十七)创建多模块Springboot项目
  • Vue.js 高质量翻页功能的完整开发指南
  • android dvr黑屏
  • css文字间距撑满横向距离
  • 【Unity基础】对比OnCollisionEnter与OnTriggerEnter
  • 算法训练(leetcode)二刷第二十五天 | *134. 加油站、*135. 分发糖果、860. 柠檬水找零、*406. 根据身高重建队列
  • Springboot 整合 itext 实现PDF文件合并,识别图片则转成PDF拼接
  • TypeScript 中的 ! 和 ? 操作符
  • 开源三代示波器的高速波形刷新方案开源,支持VNC远程桌面,手机,Pad,电脑均可访问(2024-11-11)
  • 谷歌推出设备内置人工智能,实时向手机用户发出诈骗电话警报
  • AI换人脸facefusion项目口型同步‌API化改造及部署