网站首页 > java教程 正文
大家好,我是十年程序员架构师小A。
序言
Java Jdk中的线程池问题,小A出去面试被问过四五次(前些年理解也不透彻)。而我面试别人也问过几十次,完全答对的几乎没有,多数候选人只能答对一半。
但,其实线程池以及各种其他的池化的技术都不难,原理相同、实现也很接近。一篇长文就能全部讲明白,但是为了保证技术文章足够简洁明了,不至于表面看着很长很难、半途放弃,小A准备拆分成四篇短文来彻底讲明白。
不仅讲明白线程池,也希望讲明白池化技术本身。
这四篇分别是:
- 由来,线程池有什么用?线程数设置多大合适(没那么简单,也没那么复杂)?
- 计算,IO、CPU密集型场景,分别指什么,有哪些例子?
- 思考,线程池最小最大线程、队列数设置及监控验证,流转方式?为什么这么设计?
- 类比,还有哪些池化技术,什么时候需要池化?tomcat连接池、数据库和RPC连接池。
(不要担心,每一篇都很短、很简单)
所有的编程技术本质都极其简单,只是大多数人看的是三手资料,自己就没理解透,他们写的总结学习文章是四手资料,更难理解。而我们很难找到一手资料,深入浅出很难,大多数文章来自浅入深出。
本文是讲透线程池第一篇:
第1篇,由来
线程池有什么用?
为了复用需要频繁使用到的“重”资源,以达到降低损耗进而提高性能的目的。
前半句,重点是两个词,频繁使用、“重”资源。
频繁使用:
针对后端程序来说,输入的源头都是“用户”请求,一般情况下,一个用户请求需要独立占用一个后端处理线程,而用户请求是7*24小时不间断的,假如每秒有10个用户请求,每小时需要使用的线程次数是:10*24*60*60=86万4千次。
“重”资源:
笼统来说,程序执行系统调用,需要操作系统来协助处理的时候,耗费的资源就是重资源。比如,分配一段内存、CPU分片执行计算、本机磁盘读写(磁盘IO)、网卡读写远程资源(网络IO)。
回到线程来看,根据Xss参数设置,假设是1MB。则按上述举例,假设不使用线程池,每次都是创建一个新的线程来应对(除了耗时会稍高,这么做也可以“勉强正常”运行),则每小时需要创建86万多个线程,需要的内存资源累计是860GB。
如果采用线程池,设置5个线程来复用,则所需内存资源累计是5M,资源消耗降低了近20万倍。这里仅仅说的是内存资源的角度。其实,不使用线程池,频繁创建线程也会导致线程数较多,引起cpu的来回切换,也会耗费更多的CPU资源。
复用:
用户请求来了,从线程池里“借”一个空闲线程,执行逻辑完了后,再还回池子里。然后,不断重复上述借还的动作,就是复用。(如果线程池里的线程被借完了,还有请求来了怎么办?答案是:通常情况下,进等待队列里排队,等别人先还)
后半句,重点是两个词:降低损耗、提高性能。
复用,可以降低重资源使用成本。
提高性能,一方面得益于复用,可以避免创建线程等待;另一方面,线程池还可以用于“大拆小”场景,将一个大任务拆分为n个小任务,每个小任务分配一个线程并发执行,则任务的执行时间,通常会降低到n分之一。
线程数设置多大合适(没那么简单,也没那么复杂)?
网上的文章描述,或者面试候选者的答案,通常会有如下几种:
- 使用的newCachedTheadPool,不作设置
- CPU核数左右
- IO密集型场景设置2倍核数,CPU密集1倍核数
- 先随便设置,再测试观察(“怎么测试观察?”、“不清楚”)
- 有一个复杂的公式可以计算
这些答案都不对,很多都是模棱两可的答案。主要原因,我认为有两点:1、网上或很简单,或很复杂的模棱两可的三手资料太多了,越看越不懂。2、调试线程池的高并发业务比较少,大多数人没有实操经验,纯靠二三手的理论知识很难掌握。
没那么简单:
使用newCachedTheadPool,看CPU核数这些简单的设置方法是不对的。因为没有区分计算场景,是IO还是CPU,也没有区分IO场景下不同的并发程度。
没那么复杂:
随便设置再观察测试,这个也是可以的,但是需要知道如何验证。
网上有一个复杂的计算公式,这个是比较准确的,但是有一个前提是,得是IO密集型的业务场景。
所以,设置多少:
首先,分析需要使用线程池的业务逻辑是IO密集型还是CPU密集型的。
如果是CPU密集型的业务场景:
根据需要计算资源的“多少”,分配少量资源,最大不超过CPU核数。网上很多说的是最大核心数加1,这个其实还好,只要是这个数量级下就可以。
在CPU密集下,线程数 = 最大不超过当前机器的CPU核数
(超过少量也没问题,保持一个数量级就行)
如果是IO密集型:
则可以不考虑CPU核数多少(什么意思呢?设置十倍、几十倍核数也没问题。因为绝大多数情况下在等待,不使用CPU)。主要根据两个因素来判断,并发度和每个请求处理耗时。
举例:
如果QPS=100,即每秒钟需要处理100个请求;每个请求平均处理耗时=50ms。
线程池需要设置多大才够用呢?
每个请求50ms,则一个线程1秒钟可以处理:1000ms/50ms = 20个请求。每秒钟需要处理100个请求,则需要线程数是:100个请求/20个请求 = 5个线程。
简单吧。如果非要得出一个公式出来,则简化公式如下:
在IO密集下,线程数 = QPS / (1000/单次请求耗时)
(与网上一个复杂的公式本质是一样的)
本文完。
本文针对线程数怎么设置,先讲结果,应付面试问设置数量足够了。后续三篇会继续分别解释:如何区分IO和CPU、线程池流转(运行方式)和验证、池化技术(也都非常简单)。
提示:
希望持续关注本系列及其他编程、职场、北漂相关文章的,也可以关注我的同名微信公众号:程序员Artist。
- 上一篇: 阿里巴巴Java性能调优实战:如何设置线程池大小?
- 下一篇: 编写自己的线程池
猜你喜欢
- 2024-11-23 不清楚Java线程池实现原理?那你应该收藏这篇文章!「源码分析」
- 2024-11-23 Java基础——Java多线程(线程的创建方式)
- 2024-11-23 「一文搞懂」Java线程池实现原理
- 2024-11-23 Java线程池
- 2024-11-23 java线程池实现原理以及应用场景说明
- 2024-11-23 快速弄懂Java线程池
- 2024-11-23 java线程池原理浅析
- 2024-11-23 彻底了解线程池的原理——40行从零开始自己写线程池
- 2024-11-23 Java并发编程(8):Executor框架 - 可扩展线程池WorkStealingPool
- 2024-11-23 java中的线程池
你 发表评论:
欢迎- 最近发表
-
- 五,网络安全IDA Pro反汇编工具初识及逆向工程解密实战
- 「JAVA8」- Lambda 表达式(java lambda表达式原理)
- 深入探讨Java代码保护:虚拟机保护技术的新时代
- Nginx反向代理原理详解(图文全面总结)
- 逆向拆解日本IT,哪些Java技术栈薪资溢价高
- mybatis 逆向工程使用姿势不对,把表清空了,心里慌的一比
- Spring Boot集成ProGuard轻松实现Java 代码混淆, Java 应用固若金汤
- 从 Java 代码逆向工程生成 UML 类图和序列图
- 人与人相处:尊重是标配,靠谱是高配,厚道是顶配
- Windows系统安装日期如何修改(windows10怎么修改安装日期)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)