被开发者抛弃的 Executors,错在哪儿?
yuyutoo 2024-10-12 01:36 2 浏览 0 评论
一. 序
在 Java 领域内,我们使用多线程的方式来实现并发编程。而线程本身是操作系统的一个概念,虽然不同的语言对线程都进行了一些封装,但是最终都是调用到操作系统中去创建和调度线程。
既然线程是一项重要的系统资源,为了更合理的利用此资源,我们会使用池化技术来优化线程的创建和销毁,这就是线程池。
在我们学习并发编程的时候,线程可以利用 Thread 来创建并通过 start() 来启动一个线,但在成熟的项目中,基本上是不允许这样操作线程的,都需要通过线程池去收敛线程的使用,所以线程池是必须的。
Java 的线程池可以通过 ThreadPoolExecutor 来构造,在其中提供非常完备的构造方法,可以根据我们的业务需求灵活的构造线程池。同时 Java 还提供了一个 Executors,它内部提供了很多包装的方法,利用它可以帮我们快速的构建线程池。
原本 Executors 的目的就是为了让我们更方便的使用线程池,但是《阿里巴巴Java开发手册》也明确指出,直接使用 Executors 的缺陷。
手册中提到强制不允许使用 Executors 去创建线程池,而是应该使用退化到最原始的 ThreadPoolExecutor 的方式。
日常开发中,应该收紧对线程池的创建,由开发人员明确线程池的运行规则,以此来尽量规避其资源耗尽的风险。
线程池是个好东西,但是怎么创建是一个问题。
二. Executors 怎么了?
2.1 不被允许的 Executors
不应该使用 Executors 的原因,其实《阿里巴巴Java开发手册》里已经写明了,当需要处理大量任务的时候,可能会出现 OOM 异常,但它们出现 OOM 的原因并不一样。
ThreadPoolExecutor 的构造方法中,提供了很多参数的配置,其中与 Executors 出现 OOM 相关的就有 2 个:核心线程数和等待队列。
先来看看 FixedThreadPool 和 SingleThreadPool 出现 OOM 的原因。
它们的问题在于等待队列使用了 LinkedBlockingQueue 这个以链表实现的无界队列(最大长度是 Integer.MAX_VALUE),最终导致堆积了大量等待处理的任务,从而导致频繁的 GC,最终触发 OOM。
java.lang.OutOfMemoryError: GC overhead limit exceeded
再来看看 CachedThreadPool 出现 OOM 的原因。
它的问题在于核心线程数设置为了 Integer.MAX_VALUE,并且等待队列是一个 SynchronousQueue。
SynchronousQueue 是一个没有数据缓冲的阻塞队列,它极易被阻塞。在等待队列被阻塞的时候,如果线程数量还没有达到核心线程数限制的数量时,线程池的策略是创建新的线程来处理新的任务。
也就是说,是核心线程数和等待队列 SynchronousQueue 合力造成了线程会跟随任务不断的被创建,直到触发 OOM。
java.lang.OutOfMemoryError: pthread_creat (1040KB stack) failed: Try again
ScheduledThreadPool 的等待队列使用的是 DelayedWorkQueue,原理也是类似的,最终会导致创建大量的线程而抛出 OOM。
线程是一种系统资源,本身创建就会带来内存开销,同时操作系统对单进程可创建的线程数也是有限制的。
在 Android 中,每个线程初始化都需要 mmap 一定的堆内存,在默认的情况下,初始化一个线程大约需要 mmap 1MB 左右的内存空间。同时系统本身也会对每个进程可创建的线程数,做一定的限制,这个限制在 /proc/pid/limits 中,不同的厂商对这个限制也有所不同,当超出限制时,哪怕堆上还有可用内存,依然会抛出 OOM。
2.2 Executors 错在哪儿了?
Executors 会在任务过多的时候,导致资源耗尽而触发 OOM,这是它带来的危害。
Executors 最大的问题,在于没有边界。
在系统环境良好,任务不多的时候 Executors 创建的线程池,都是可以正常工作的。
但是一旦有重压,我们就无法预知什么时候会出现问题,这就是没有边界,没有边界就意味着不可控。
我们很难去信任一段不可控的代码,它什么时候出现问题,完全是不可预知的,这才是 Executors 最大的问题。
除此之外,Executors 封装了太多线程池的细节,本身也不建议使用。例如通常我们需要給线程池创建的线程,起一个有意义的名称,方便在出现异常的时候排查问题;再例如对与线程池的拒绝策略,我们需要深思熟虑的定义,是直接抛弃还是持久化下来延迟处理。
去思考一个线程池的不同参数带来的策略细节,才是使用线程池的一个良好的开发习惯。
三. 小结时刻
本文我们聊了关于创建线程池,使用 Executors 创建的线程池会有 OOM 的风险,应该使用 ThreadPoolExecutor 去创建线程池。通过思考业务来明确配置线程池不同的参数,例如线程池、等待队列、拒绝策略等等。
今天就到这里,有任何问题,欢迎留言讨论。
本文对你有帮助吗?留言、转发、点赞是最大的支持,谢谢!
在头条号私信我。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。
相关推荐
- jQuery VS AngularJS 你更钟爱哪个?
-
在这一次的Web开发教程中,我会尽力解答有关于jQuery和AngularJS的两个非常常见的问题,即jQuery和AngularJS之间的区别是什么?也就是说jQueryVSAngularJS?...
- Jquery实时校验,指定长度的「负小数」,小数位未满末尾补0
-
在可以输入【负小数】的输入框获取到焦点时,移除千位分隔符,在输入数据时,实时校验输入内容是否正确,失去焦点后,添加千位分隔符格式化数字。同时小数位未满时末尾补0。HTML代码...
- 如何在pbootCMS前台调用自定义表单?pbootCMS自定义调用代码示例
-
要在pbootCMS前台调用自定义表单,您需要在后台创建表单并为其添加字段,然后在前台模板文件中添加相关代码,如提交按钮和表单验证代码。您还可以自定义表单数据的存储位置、添加文件上传字段、日期选择器、...
- 编程技巧:Jquery实时验证,指定长度的「负小数」
-
为了保障【负小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【负小数】的方法。HTML代码<inputtype="text"class="forc...
- 一篇文章带你用jquery mobile设计颜色拾取器
-
【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...
- 编程技巧:Jquery实时验证,指定长度的「正小数」
-
为了保障【正小数】的正确性,做成了通过Jquery,在用户端,实时验证指定长度的【正小数】的方法。HTML做成方法<inputtype="text"class="fo...
- jquery.validate检查数组全部验证
-
问题:html中有多个name[],每个参数都要进行验证是否为空,这个时候直接用required:true话,不能全部验证,只要这个数组中有一个有值就可以通过的。解决方法使用addmethod...
- Vue进阶(幺叁肆):npm查看包版本信息
-
第一种方式npmviewjqueryversions这种方式可以查看npm服务器上所有的...
- layui中使用lay-verify进行条件校验
-
一、layui的校验很简单,主要有以下步骤:1.在form表单内加上class="layui-form"2.在提交按钮上加上lay-submit3.在想要校验的标签,加上lay-...
- jQuery是什么?如何使用? jquery是什么功能组件
-
jQuery于2006年1月由JohnResig在BarCampNYC首次发布。它目前由TimmyWilson领导,并由一组开发人员维护。jQuery是一个JavaScript库,它简化了客户...
- django框架的表单form的理解和用法-9
-
表单呈现...
- jquery对上传文件的检测判断 jquery实现文件上传
-
总体思路:在前端使用jquery对上传文件做部分初步的判断,验证通过的文件利用ajaxFileUpload上传到服务器端,并将文件的存储路径保存到数据库。<asp:FileUploadI...
- Nodejs之MEAN栈开发(四)-- form验证及图片上传
-
这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/R...
- 大数据开发基础之JAVA jquery 大数据java实战
-
上一篇我们讲解了JAVAscript的基础知识、特点及基本语法以及组成及基本用途,本期就给大家带来了JAVAweb的第二个知识点jquery,大数据开发基础之JAVAjquery,这是本篇文章的主要...
- 推荐四个开源的jQuery可视化表单设计器
-
jquery开源在线表单拖拉设计器formBuilder(推荐)jQueryformBuilder是一个开源的WEB在线html表单设计器,开发人员可以通过拖拉实现一个可视化的表单。支持表单常用控件...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)