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 {
-
- @Resource
- private SyncTask syncTask;
- @Test
- public 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();
- @Async
- public void one() throws InterruptedException {
- commonTask("一");
- }
- @Async
- public void two() throws InterruptedException {
- commonTask("二");
- }
- @Async
- 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
- @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();
- @Async
- public 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("任务一执行完成");
- }
- @Async
- public 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("任务二执行完成");
- }
- @Async
- public 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
- @Resource
- private AsyncCallBackTask asyncCallBackTask;
- @Test
- public 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 #线程池创建时的初始化线程数,默认为8
- max-size: 5 #线程池的最大线程数,默认为int最大值
- queue-capacity: 10 #用来缓冲执行任务的队列,默认为int最大值
- keep-alive: 60s #线程终止前允许保持空闲的时间,默认为60s
- allow-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】
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |