很多人都知道阿里的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: