SpringBoot之SpringBoot整合异步线程调用注解
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
作者 | 彼岸舞
来源 | urlify.cn/a6ryIz
理念:
为了快速响应浏览器,开启多线程执行任务
但是有一个缺点,会增加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了,线程池的参数可以根据自己项目的实际情况调整,不懂线程池的可以去看看我写的《线程池理念分析及其手写》
到此整合异步注解完成
粉丝福利:Java从入门到入土学习路线图
👇👇👇
👆长按上方微信二维码 2 秒
感谢点赞支持下哈
评论