shigen
坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。 个人IP:shigen
在shigen
之前的很多文章中,提到了线程池:
-
• 高性能API设计[1]
-
• 一文讲清楚redis的线程池jedis[2]
并配有对应的原理图:

在今天重学的时候,遇到了这样的问题:准备去封装一个线程池的,看到了异步线程池的概念。什么?异步线程池,重新复习了一下。意外收获了一个注解Async
。
首先,理解一下异步的概念:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态。能联系到的最佳的场景是:我要下载文件,文件要能生成很长的时间,不能一直等待对吧。在我的文章《高性能API设计》中就提到了异步思想。

OK,那就直接上代码吧。
简单的controller、service:
@GetMapping(value = "download")
public String download() {
log.info("开始下载-------");
testService.downloadFile();
log.info("下载完成-------");
return "download";
}
@SneakyThrows
public void downloadFile() {
log.info("开始-------");
Thread.sleep(10*1000);
log.info("结束-------");
}
相信很多人都是这样写的,那再好的服务器,找个借口的响应时间都是10s+。是的,另一端的用户就准备好台词在心里骂设计者100遍了。
一次请求就是一个线程,这个线程一直在耗时的文件下载阶段,能不阻塞才怪。现在,优化点在于实现文件导出的异步。
看代码:
定义线程池配置类
写烂了,直接复制粘贴。
@Configuration
public class AsyncConfig {
@Bean("asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数:线程池创建时候初始化的线程数
executor.setCorePoolSize(10);
// 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(20);
// 缓冲队列:用来缓冲执行任务的队列
executor.setQueueCapacity(500);
// 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
// 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("async-shigen-");
// 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
没啥好说的,就是线程的名字带了shigen
,便于区分。
主配置类
加上注解EnableAsync
即可。
@SpringBootApplication
@EnableAsync
@MapperScan(basePackages = "com.shigen.demo.dao")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
实现类
实现类用的时候就需要线程池了。
@Service("testService")
@Slf4j
public class TestServiceImpl {
/**
* 不能和调用方放在同一个类中
* <a href="https://blog.csdn.net/weixin_45151960/article/details/133988933">参考文章</a>
*/
@SneakyThrows
@Async("asyncExecutor")
public void downloadFile() {
log.info("开始-------");
Thread.sleep(10*1000);
log.info("结束-------");
}
}
代码中已经注明:异步方法不能和调用方放在同一个类中。
参考文章:
-
• Springboot中开启多线程,实现异步非阻塞、异步阻塞、有无返回值的场景[3]
-
• 文章代码[4]
测试
本来需要10s+的响应时间,现在已经是不到1s了。输出的日志如下:

表明文件的下载在单独的处理。
最后总结一下参考的博客中的几种场景:
场景 | API |
异步非阻塞无返回值 | EnableAsync Async |
异步非阻塞又返回值 | 场景不存在 |
异步阻塞无返回值 | CountDownLatch Async |
异步阻塞又返回值 | CompletableFuture Async |
与shigen一起,每天不一样!
引用链接
[1]
高性能API设计: https://juejin.cn/post/7262920080203399227[2]
一文讲清楚redis的线程池jedis: https://juejin.cn/post/7274211579691859983[3]
Springboot中开启多线程,实现异步非阻塞、异步阻塞、有无返回值的场景: https://blog.csdn.net/weixin_45151960/article/details/133988933[4]
文章代码: https://gitee.com/shigen/study/commit/14757387dec8bfbe112e75060c0ee9797a295892
原文始发于微信公众号(shigen):spring boot使用异步多线程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/230971.html