热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot项目@Async默认线程池导致OOM问题?:springboot默认线程池

本文主要分享【springboot默认线程池】,技术文章【SpringBoot项目@Async默认线程池导致OOM问题?】为【赵侠客】投稿,如果你遇到Java相关问题,本文相关知识或能到你。spr

本文主要分享【springboot 默认线程池】,技术文章【SpringBoot项目@Async默认线程池导致OOM问题?】为【赵侠客】投稿,如果你遇到Java相关问题,本文相关知识或能到你。

springboot 默认线程池

写在前面

最近看到很一篇文章说SpringBoot项目中@Async默认线程池会导致OOM,因为我的项目中也用到@Async注解,所以赶紧看了一下,在网上搜索@Async导致OOM案例还是很多的,于是我我就研究了一下。

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

Demo项目演示

使用SpringBoot 2.0.9.RELEASE 创建演示工程,项目比较简单,使用@EnableAsync开启异步,在TaskService中@Async开启方法异步。

@SpringBootApplication
@EnableAsync
@RestController
public class AsyncDemoApplication {
    @Resource
    private TaskService taskService;
    @GetMapping("/id")
    public String test()  {
        taskService.deel();
        return "ok";
    }
    public static void main(String[] args) {
        SpringApplication.run(AsyncDemoApplication.class, args);
    }
}
@Component
@Slf4j
public class TaskService {

    @Async
    public void deel()  {
        log.info("Thread Name :{} ", Thread.currentThread().getName());
    }
}
压测实验

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

从压测结果上来看,刚一开始等待线程数就有3024条,日志中SimpleAsyncTaskExecutor-11922 编号已达到11922个了,看来确实和网上说的一样 @Async默认线程池是SimpleAsyncTaskExecutor,会每次创建一个线程去执行任务,任务量大了会产生OOM。

关键代码:

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

protected void doExecute(Runnable task) {
   Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
   thread.start();
}

在SimpleAsyncTaskExecutor的doExecute方法中每次会创建新线程来执行,所以导致瞬间等待线程数达到3024条,确实有点坑人。

升级SpringBoot到2.1.0.RELEASE重新压测

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

升级后结果完全不同了,线程数量并没有上升,线程名也变成task-8 这样的了,看来是SpringBoot 优化掉了这个 SimpleAsyncTaskExecutor

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

在2.1.0之后的版本多了一个TaskExecutionAutoConfiguration,在项目缺少 Executor Bean的情况下注入了一个ThreadPoolTaskExecutor,作为@Async默认线程池。

SpringBoot 2.0.9.RELEASE配置线程池后再测试

@SpringBootApplication
@EnableAsync
@RestController
public class AsyncDemoApplication {

    @Bean("fileTask")
    public Executor fileTask() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(40);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("file-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
    @Resource
    private TaskService taskService;

    @GetMapping("/id")
    public String test() {
        taskService.deel();
        return "ok";
    }

    public static void main(String[] args) {
        SpringApplication.run(AsyncDemoApplication.class, args);
    }

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

从测试结果来看是没有问题,使用项目中配置的fileTask

配置多个线程池测试
@SpringBootApplication
@EnableAsync
@RestController
public class AsyncDemoApplication {

    @Bean("fileTask")
    public Executor fileTask() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(40);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("file-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    @Bean("imgTask")
    public Executor imgTask() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(40);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("img-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    @Resource
    private TaskService taskService;

    @GetMapping("/id")
    public String test() {
        taskService.deel();
        return "ok";
    }

    public static void main(String[] args) {
        SpringApplication.run(AsyncDemoApplication.class, args);
    }

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

如果项目中配置了多个Executor也会使用 SimpleAsyncTaskExecutor

SpringBoot项目@Async默认线程池导致OOM问题?:springboot 默认线程池

原因是在AsyncExecutionInterceptor 中调用 getDefaultExecutor() 时beanFactory.getBean(TaskExecutor.class) 找到了两个bean所以 报了 NoUniqueBeanDefinitionException,导致没获取到Executor而使用了SimpleAsyncTaskExecutor,所以在fileTask 添加@Primary可解决多个bean问题。

总结 SpringBoot 2.1.9 之前版本 使用@Async 不指定 Executor 会使用 SimpleAsyncTaskExecutor,任务量大会导致OOM, SpringBoot 2.1.0之后版本 引入了 TaskExecutionAutoConfiguration使用
ThreadPoolTaskExecutor作为默认 Executor;当项目中有多个 Executor 实列时也会使用 SimpleAsyncTaskExecutor,导致OOM,建议@Primary指定主Bean;@Async是可以使用的,最好指定线程池,使用越简单,隐藏问题就越多。

本文《SpringBoot项目@Async默认线程池导致OOM问题?》版权归赵侠客所有,引用SpringBoot项目@Async默认线程池导致OOM问题?需遵循CC 4.0 BY-SA版权协议。


推荐阅读
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
author-avatar
四川盛地地产顾问有限公司_255
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有