SpringBoot之SpringBoot整合异步线程调用注解
理念:
为了快速响应浏览器,开启多线程执行任务
但是有一个缺点,会增加CPU资源的消耗,所以大的项目推荐使用MQ消息队列
编写代码:
@GetMapping("/addDB") public String addDB() { // 模拟数据交互 log.info("<01>"); sms(); log.info("<04>"); return "用户注册成功"; } /** * 模拟发送短信 * * @return */ public String sms() { log.info("<02>"); try { log.info("正在发送短信..."); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "短信发送完成"; }
这个接口最少需要4秒才能返回,如果发送短信时间更长,返回时间增加,这样用户的体验就非常不好
启动项目测试
他是单线程去执行的,看过Tomcat的应该也知道,tomcat会为每一次请求从他的线程池中单独拿一个线程去执行,所以它是单线程 的
所以这里就可以使用Spring提供的异步注解
异步注解的使用:
在方法上添加@Async注解
并且在启动类中开启异步注解
启动测试:
不对呀,这还是单线程呀
异步注解失效问题解决:
需要把sms方法单独提取成一个类
package com.springboot.demo.async; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; /** * @author ZYGisComputer */ @Slf4j @Component public class SmsService { /** * 模拟发送短信 * * @return */ @Async public String sms() { log.info("<02>"); try { log.info("正在发送短信..."); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return "短信发送完成"; } }
通过Autowirld的方式注入使用
再次测试
可以看到执行成功了,并且也是不同的线程,但是他这样都是每次都是new一个新的线程,这显然是不合理的,因为使用线程就应该考虑采用线程池
异步注解整合线程池:
创建config包,并在下面创建ThreadPoolConfig.java
package com.springboot.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @EnableAsync public class ThreadPoolConfig { /** * 每秒需要多少个线程处理? * tasks/(1/taskcost) */ private int corePoolSize = 3; /** * 线程池维护线程的最大数量 * (max(tasks)- queueCapacity)/(1/taskcost) */ private int maxPoolSize = 3; /** * 缓存队列 * (coreSizePool/taskcost)*responsetime */ private int queueCapacity = 10; /** * 允许的空闲时间 * 默认为60 */ private int keepAlive = 100; @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 设置核心线程数 executor.setCorePoolSize(corePoolSize); // 设置最大线程数 executor.setMaxPoolSize(maxPoolSize); // 设置队列容量 executor.setQueueCapacity(queueCapacity); // 设置允许的空闲时间(秒) //executor.setKeepAliveSeconds(keepAlive); // 设置默认线程名称 executor.setThreadNamePrefix("thread-"); // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务 // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任务结束后再关闭线程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
在@Async注解中配置线程池名称就可以
启动项目测试:
2021-01-26 18:18:53,820 [http-nio-8082-exec-1] INFO (HelloService.java:76)- <01> 2021-01-26 18:18:53,823 [http-nio-8082-exec-1] INFO (HelloService.java:78)- <04> 2021-01-26 18:18:53,823 [http-nio-8082-exec-1] INFO (LogAspect.java:50)- RESPONSE : 用户注册成功 2021-01-26 18:18:53,829 [thread-1] INFO (SmsService.java:24)- <02> 2021-01-26 18:18:53,831 [thread-1] INFO (SmsService.java:26)- 正在发送短信... <执行定时任务>:18:18:56 <执行定时任务>:18:19:01 2021-01-26 18:19:01,340 [http-nio-8082-exec-3] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:01,341 [http-nio-8082-exec-3] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:01,342 [http-nio-8082-exec-3] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:01,342 [thread-2] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:01,342 [thread-2] INFO (SmsService.java:26)- 正在发送短信... 2021-01-26 18:19:01,342 [http-nio-8082-exec-3] INFO (LogAspect.java:50)- RESPONSE : 用户注册成功 2021-01-26 18:19:01,922 [http-nio-8082-exec-4] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:01,922 [http-nio-8082-exec-4] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:01,923 [http-nio-8082-exec-4] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:01,924 [thread-3] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:01,924 [http-nio-8082-exec-4] INFO (LogAspect.java:50)- RESPONSE : 用户注册成功 2021-01-26 18:19:01,924 [thread-3] INFO (SmsService.java:26)- 正在发送短信... 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:37)- URL : http://localhost:8082/addDB 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:38)- HTTP_METHOD : GET 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (LogAspect.java:39)- IP : 0:0:0:0:0:0:0:1 2021-01-26 18:19:02,559 [http-nio-8082-exec-2] INFO (HelloService.java:76)- <01> 2021-01-26 18:19:02,560 [thread-1] INFO (SmsService.java:24)- <02> 2021-01-26 18:19:02,560 [http-nio-8082-exec-2] INFO (HelloService.java:78)- <04> 2021-01-26 18:19:02,560 [thread-1] INFO (SmsService.java:26)- 正在发送短信... 2021-01-26 18:19:02,560 [http-nio-8082-exec-2] INFO (LogAspect.java:50)- RESPONSE : 用户注册成功
可以看到使用完成thread-3之后使用的又是thread-1了,线程池的参数可以根据自己项目的实际情况调整,不懂线程池的可以去看看我写的《线程池理念分析及其手写》
到此整合异步注解完成
作者:彼岸舞
时间:2021 126
内容关于:SpringBoot
本文来源于网络,只做技术分享,一概不负任何责任