从Executors和ThreadPoolExecutor的区别分析到线程池的OOM

本文分析了为什么阿里巴巴禁止使用Executors创建线程池,原因是可能导致资源耗尽,特别是当使用默认参数时,可能会创建大量线程。通过举例说明了通过ThreadPoolExecutor自定义参数可以避免此类问题,但如果不恰当配置等待队列,仍然可能出现OOM。文章通过不同场景的示例演示了线程池配置不当如何触发OOM,并提到了监控工具Arthas在排查问题中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多人都知道阿里的Java开发严令禁止使用Executors的方式来创建线程池,禁止的理由是“为了让开发者更加明确线程池的运行规则,更加了解线程池的底层工作原理,从而避免不规范的使用造成服务器资源耗尽的风险”,本菜鸡曾经也是在UC原生团队呆过一年,在内部的开发手册上也确实记录了很多这些Java ,mysql的规范。当时由于业务繁忙,也没深究,造成了极大的浪费,其实很矛盾,带我的那位私有云的架构师大佬每天都叫我多学习,但是本菜鸡每天都在堆砌着业务逻辑代码,加班完回家一般都九点十点了,自己偷偷懒,又不看了。于是造成了他对我很失望,也不热衷于多问他问题,觉得我很浪费身边的资源,不好学,几次告诫我以后离职的话会后悔,学习是为了自己的。现在熬不住福报,离职了,当事人心里确实非常后悔,要是再给一次重来的机会,一定把业务和学习任务齐头并进!把他脑汁都榨干了再走!现在,宝宝心里苦也是说不出…
扯远了不好意思…这篇文章不是吹水文,下面开始正题。
首先要了解什么是线程池。可以看:线程池的简单的底层解析和使用
一:通过Executors方式创建:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
二:通过ThreadPoolExecutor方式创建:
 ExecutorService cachedThreadPool = new ThreadPoolExecutor(1,3,10, TimeUnit.SECONDS,arrayBlockingQueue);
第一个问题可以看出,Executors方式创建可以不需要传一些参数,那么这些参数是什么呢?我们都知道线程池要有最大线程数,核心线程数和过期时间和等待队列…那么不传,就是用的默认,那么默认的是多少呢?点进去一看!

在这里插入图片描述
在这里插入图片描述

cachedThreadPool缓存线程池中,假如不指定默认的corePoolSize最大线程数,那么因为它是无界的,就会一直根据任务来创建线程。核心线程数默认0,最大线程数2147483647.。。。二十一亿四千七百多万。很明显,我们的内存根本吃不起这个数量的默认最大线程数。
而ThreadPoolExecutor方式创建则要求我们一定要传入参数,我们就可以按照正常的最优线程数计算公式来计算我们要开启的线程。

在这里插入图片描述

所以这个时候,我们就可以知道,所谓的服务器资源耗尽,就是JVM内存耗尽,也称Out Of Memory(OOM)。
OOM情况一:

就是上面说的那样,Executors创建方式因为可以不传参数而使用默认值进行线程池的创建,所以在不规范使用的场景下就很容易导致无边界线程池开启了过多的线程,从而导致OOM。
多说无益,上demo:
在这里插入图片描述

由于我忘了调小JVM的内存分配,所以这里创建到了上千万还在创建。但是通过阿里那个Arthas工具(博客:Java系统性能监控工具Arthas的使用)可以看到线程们的执行情况:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值