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

打印 上一主题 下一主题

主题 1008|帖子 1008|积分 3024

Git堆栈

https://gitee.com/Lin_DH/system
介绍

同步调用:指程序在实验时,调用方需要等待函数调用返回结果后,才气继续实验下一步操作,是一种壅闭式调用。
异步调用:指程序在实验时,调用方在调用函数后立即返回,不需要等待函数调用返回结果,可以直接实验下一步操作,当函数实验完成后,会通过回调或其他方式关照调用方,得到返回结果。
回调:在调用一个函数后,需要在函数实验中或实验后,将实验结果或状态返回给调用者。
代码实现

第一步:启动类上添加 @EnableAsync 注解,开启异步功能。
  1. @EnableAsync
  2. @SpringBootApplication
  3. public class SystemApplication extends SpringBootServletInitializer {}
复制代码
同步调用

第二步:添加同步调用业务逻辑
注:@Async 注解不能修饰的 static 修饰的函数,该类型的函数异步调用不会见效。
  1. package com.lm.system.task;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.stereotype.Component;
  4. import java.util.Random;
  5. /**
  6. * 同步调用
  7. * @author DUHAOLIN
  8. * @date 2024/10/17
  9. */
  10. @Slf4j
  11. @Component
  12. public class SyncTask {
  13.     public static Random random = new Random();
  14.     public void one() throws InterruptedException {
  15.         commonTask("一");
  16.     }
  17.    
  18.     public void two() throws InterruptedException {
  19.         commonTask("二");
  20.     }
  21.     public void three() throws InterruptedException {
  22.         commonTask("三");
  23.     }
  24.     public void commonTask(String s) throws InterruptedException {
  25.         log.info("开始执行任务" + s);
  26.         long startTime = System.currentTimeMillis();
  27.         Thread.sleep(random.nextInt(10000));
  28.         long endTime = System.currentTimeMillis();
  29.         log.info("完成任务" + s + ",耗时:" + (endTime - startTime) + "毫秒");
  30.     }
  31. }
复制代码
第三步:测试类添加同步调用的测试方法
   SystemApplicationTests.java
  1. @Slf4j
  2. @SpringBootTest(classes = SystemApplication.class)
  3. class SystemApplicationTests {
  4.    
  5.     @Resource
  6.     private SyncTask syncTask;
  7.     @Test
  8.     public void syncTest() throws InterruptedException {
  9.         long startTime = System.currentTimeMillis();
  10.         syncTask.one();
  11.         syncTask.two();
  12.         syncTask.three();
  13.         long endTime = System.currentTimeMillis();
  14.         log.info("任务总耗时:" + (endTime - startTime) + "毫秒");
  15.     }
  16.    
  17. }
复制代码
异步调用

第四步:添加异步调用业务逻辑
   AsyncTask.java
  1. /**
  2. * 异步调用
  3. * @author DUHAOLIN
  4. * @date 2024/10/17
  5. */
  6. @Slf4j
  7. @Component
  8. public class AsyncTask {
  9.     public static Random random = new Random();
  10.     @Async
  11.     public void one() throws InterruptedException {
  12.         commonTask("一");
  13.     }
  14.     @Async
  15.     public void two() throws InterruptedException {
  16.         commonTask("二");
  17.     }
  18.     @Async
  19.     public void three() throws InterruptedException {
  20.         commonTask("三");
  21.     }
  22.     public void commonTask(String s) throws InterruptedException {
  23.         log.info("开始执行任务" + s);
  24.         long startTime = System.currentTimeMillis();
  25.         Thread.sleep(random.nextInt(10000));
  26.         long endTime = System.currentTimeMillis();
  27.         log.info("完成任务" + s + ",耗时:" + (endTime - startTime) + "毫秒");
  28.     }
  29. }
复制代码
第五步:测试类添加异步调用的测试方法
   SystemApplicationTests.java
  1. @Resource
  2. private AsyncTask asyncTask;
  3. @Test
  4. public void asyncTest() throws InterruptedException {
  5.     long startTime = System.currentTimeMillis();
  6.     asyncTask.one();
  7.     asyncTask.two();
  8.     asyncTask.three();
  9.     long endTime = System.currentTimeMillis();
  10.     log.info("任务总耗时:" + (endTime - startTime) + "毫秒");
  11. }
复制代码
异步回调(常用)

第六步:添加异步回调业务逻辑
   AsyncCallBackTask.java
  1. package com.lm.system.task;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.scheduling.annotation.Async;
  4. import org.springframework.stereotype.Component;
  5. import java.util.Random;
  6. package com.lm.system.task;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.scheduling.annotation.Async;
  9. import org.springframework.stereotype.Component;
  10. import java.util.Random;
  11. import java.util.concurrent.CompletableFuture;
  12. /**
  13. * 异步回调
  14. * @author DUHAOLIN
  15. * @date 2024/10/17
  16. */
  17. @Slf4j
  18. @Component
  19. public class AsyncCallBackTask {
  20.     public static Random random = new Random();
  21.     @Async
  22.     public CompletableFuture<String> one() throws InterruptedException {
  23.         log.info("开始执行任务一");
  24.         long startTime = System.currentTimeMillis();
  25.         Thread.sleep(random.nextInt(10000));
  26.         long endTime = System.currentTimeMillis();
  27.         log.info("完成任务一,耗时:" + (endTime - startTime) + "毫秒");
  28.         return CompletableFuture.completedFuture("任务一执行完成");
  29.     }
  30.     @Async
  31.     public CompletableFuture<String> two() throws InterruptedException {
  32.         log.info("开始执行任务二");
  33.         long startTime = System.currentTimeMillis();
  34.         Thread.sleep(random.nextInt(10000));
  35.         long endTime = System.currentTimeMillis();
  36.         log.info("完成任务二,耗时:" + (endTime - startTime) + "毫秒");
  37.         return CompletableFuture.completedFuture("任务二执行完成");
  38.     }
  39.     @Async
  40.     public CompletableFuture<String> three() throws InterruptedException {
  41.         log.info("开始执行任务三");
  42.         long startTime = System.currentTimeMillis();
  43.         Thread.sleep(random.nextInt(10000));
  44.         long endTime = System.currentTimeMillis();
  45.         log.info("完成任务三,耗时:" + (endTime - startTime) + "毫秒");
  46.         return CompletableFuture.completedFuture("任务三执行完成");
  47.     }
  48. }
复制代码
第七步:测试类添加异步回调的测试方法
   SystemApplicationTests.java
  1. @Resource
  2.     private AsyncCallBackTask asyncCallBackTask;
  3.     @Test
  4.     public void asyncCallBackTaskTest() throws InterruptedException {
  5.         long startTime = System.currentTimeMillis();
  6.         CompletableFuture<String> one = asyncCallBackTask.one();
  7.         CompletableFuture<String> two = asyncCallBackTask.two();
  8.         CompletableFuture<String> three = asyncCallBackTask.three();
  9.         CompletableFuture.allOf(one, two, three).join();
  10.         long endTime = System.currentTimeMillis();
  11.         log.info("任务总耗时:" + (endTime - startTime) + "毫秒");
  12.     }
复制代码
结果图

同步调用

异步调用
实验完异步调用,只有使命的部分相关输出,使命的实验顺序也是乱序的。

异步回调

异步使命线程池设置

介绍

当我们用异步调用或异步回调进行并发操作时,加速了使命的实验效率,但是假如只是直接简单的创建来使用,可能会碰到一些问题和风险。当接口被频繁调用,异步使命创建的数量到达一定量级,可能会导致内存溢出,此时我们就需要对创建异步使命的操作,加上线程池的相关设置。

queueCapacity:缓冲队列的容量,默认为INT的最大值(2的31次方-1)
maxSize:允许的最大线程数,默认为INT的最大值(2的31次方-1)
具体设置


   application.yml
  1. spring:
  2.   task:
  3.     execution:
  4.       pool:
  5.         core-size: 2 #线程池创建时的初始化线程数,默认为8
  6.         max-size: 5 #线程池的最大线程数,默认为int最大值
  7.         queue-capacity: 10 #用来缓冲执行任务的队列,默认为int最大值
  8.         keep-alive: 60s #线程终止前允许保持空闲的时间,默认为60s
  9.         allow-core-thread-timeout: true #是否允许核心线程超时
  10.       shutdown:
  11.         await-termination: false #是否等待剩余任务完成后才关闭应用
  12.         await-termination-period: #等待剩余任务完成的最大时间
  13.       thread-name-prefix: task- #线程名的前缀,设置好了之后可以方便我们在日志中查看处理任务所在的线程池
复制代码
  application.Properties
  1. spring.task.execution.pool.core-size=2
  2. spring.task.execution.pool.max-size=5
  3. spring.task.execution.pool.queue-capacity=10
  4. spring.task.execution.pool.keep-alive=60s
  5. spring.task.execution.pool.allow-core-thread-timeout=true
  6. spring.task.execution.shutdown.await-termination=false
  7. spring.task.execution.shutdown.await-termination-period=
  8. 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】

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

花瓣小跑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表