被开发者抛弃的 Executors,错在哪儿?
yuyutoo 2024-10-12 01:36 9 浏览 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项目源码。
相关推荐
- Python操作Word文档神器:python-docx库从入门到精通
-
Python操作Word文档神器:python-docx库从入门到精通动动小手,点击关注...
- Python 函数调用从入门到精通:超详细定义解析与实战指南 附案例
-
一、函数基础:定义与调用的核心逻辑定义:函数是将重复或相关的代码块封装成可复用的单元,通过函数名和参数实现特定功能。它是Python模块化编程的基础,能提高代码复用性和可读性。定义语法:...
- 等这么长时间Python背记手册终于来了,入门到精通(视频400集)
-
本文毫无套路!真诚分享!前言:无论是学习任何一门语言,基础知识一定要扎实,基础功非常的重要,找一个有丰富编程经验的老师或者师兄带着你会少走很多弯路,你的进步速度也会快很多,无论我们学习的目的是什么,...
- 图解Python编程:从入门到精通系列教程(附全套速查表)
-
引言本系列教程展开讲解Python编程语言,Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,它也是互联网最热门的编程语言之一。Python生态丰富,库(模块)极其丰富,这使...
- Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够
-
本书是Python经典实例解析,采用基于实例的方法编写,每个实例都会解决具体的问题和难题。主要内容有:数字、字符串和元组,语句与语法,函数定义,列表、集、字典,用户输入和输出等内置数据结构,类和对象,...
- Python函数全解析:从入门到精通,一文搞定!
-
1.为什么要用函数?函数的作用:封装代码,提高复用性,减少重复,提高可读性。...
- Python中的单例模式:从入门到精通
-
Python中的单例模式:从入门到精通引言单例模式是一种常用的软件设计模式,它保证了一个类只有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁创建和销毁的对象,比如日志对象、线程池、缓存等...
- 【Python王者归来】手把手教你,Python从入门到精通!
-
用800个程序实例、5万行代码手把手教你,Python从入门到精通!...
- Python从零基础入门到精通:一个月就够了
-
如果想从零基础到入门,能够全职学习(自学),那么一个月足够了。...
- Python 从入门到精通:一个月就够了
-
要知道,一个月是一段很长的时间。如果每天坚持用6-7小时来做一件事,你会有意想不到的收获。作为初学者,第一个月的月目标应该是这样的:熟悉基本概念(变量,条件,列表,循环,函数)练习超过30个编...
- Python零基础到精通,这8个入门技巧让你少走弯路,7天速通编程!
-
Python学习就像玩积木,从最基础的块开始,一步步搭建出复杂的作品。我记得刚开始学Python时也是一头雾水,走了不少弯路。现在回头看,其实掌握几个核心概念,就能快速入门这门编程语言。来聊聊怎么用最...
- 神仙级python入门教程(非常详细),从0到精通,从看这篇开始!
-
python入门虽然简单,很多新手依然卡在基础安装阶段,大部分教程对一些基础内容都是一带而过,好多新手朋友,对一些基础知识常常一知半解,需要在网上查询很久。...
- Python类从入门到精通,一篇就够!
-
一、Python类是什么?大家在生活中应该都见过汽车吧,每一辆真实存在、能在路上跑的汽车,都可以看作是一个“对象”。那这些汽车是怎么生产出来的呢?其实,在生产之前,汽车公司都会先设计一个详细的蓝图...
- 学习Python从入门到精通:30天足够了,这才是python基础的天花板
-
当年2w买的全套python教程用不着了,现在送给有缘人,不要钱,一个月教你从入门到精通1、本套视频共487集,本套视频共分4季...
- 30天Python 入门到精通(3天学会python)
-
以下是一个为期30天的Python入门到精通学习课程,专为零基础新手设计。课程从基础语法开始,逐步深入到面向对象编程、数据处理,最后实现运行简单的大语言模型(如基于HuggingFace...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 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)