Java 并发编程实战
王宝令
资深架构师
72485 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

10 | Java线程(中):创建多少线程才是合适的?

最佳线程数 = CPU核数 * [ 1 + (I/O耗时 / CPU耗时) ]
最佳线程数 = 1 + (I/O耗时 / CPU耗时)
线程数量 = CPU核数 + 1 (工程上)
线程数量 = CPU核数
CPU
I/O设备
将硬件的性能发挥到极致
I/O密集型计算
CPU密集型计算
硬件的性能发挥
优化算法
吞吐量
延迟
课后思考
总结
创建多少线程合适?
多线程的应用场景
为什么要使用多线程?
Java中创建多少线程才是合适的?

该思维导图由 AI 生成,仅供参考

在 Java 领域,实现并发程序的主要手段就是多线程,使用多线程还是比较简单的,但是使用多少个线程却是个困难的问题。工作中,经常有人问,“各种线程池的线程数量调整成多少是合适的?”或者“Tomcat 的线程数、Jdbc 连接池的连接数是多少?”等等。那我们应该如何设置合适的线程数呢?
要解决这个问题,首先要分析以下两个问题:
为什么要使用多线程?
多线程的应用场景有哪些?

为什么要使用多线程?

使用多线程,本质上就是提升程序性能。不过此刻谈到的性能,可能在你脑海里还是比较笼统的,基本上就是快、快、快,这种无法度量的感性认识很不科学,所以在提升性能之前,首要问题是:如何度量性能。
度量性能的指标有很多,但是有两个指标是最核心的,它们就是延迟和吞吐量。延迟指的是发出请求到收到响应这个过程的时间;延迟越短,意味着程序执行得越快,性能也就越好。 吞吐量指的是在单位时间内能处理请求的数量;吞吐量越大,意味着程序能处理的请求越多,性能也就越好。这两个指标内部有一定的联系(同等条件下,延迟越短,吞吐量越大),但是由于它们隶属不同的维度(一个是时间维度,一个是空间维度),并不能互相转换。
我们所谓提升性能,从度量的角度,主要是降低延迟,提高吞吐量。这也是我们使用多线程的主要目的。那我们该怎么降低延迟,提高吞吐量呢?这个就要从多线程的应用场景说起了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文从性能度量的角度出发,介绍了多线程的应用场景和最佳线程数的计算方法。文章首先强调了性能度量的核心指标是延迟和吞吐量,解释了为什么要使用多线程。接着详细阐述了多线程的应用场景,包括优化算法和提高硬件利用率。针对CPU密集型和I/O密集型计算场景,提出了最佳线程数的计算方法。对于CPU密集型计算,最佳线程数为CPU核数加一;而对于I/O密集型计算,最佳线程数与程序中CPU计算和I/O操作的耗时比相关。最后总结了将硬件性能发挥到极致的原则,并强调了在工程上需要估算关键参数并进行压测验证。整体而言,本文通过理论分析和实际应用,为读者提供了创建合适线程数的指导原则。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(132)

  • 最新
  • 精选
  • 假行僧
    个人觉得公式话性能问题有些不妥,定性的io密集或者cpu密集很难在定量的维度上反应出性能瓶颈,而且公式上忽略了线程数增加带来的cpu消耗,性能优化还是要定量比较好,这样不会盲目,比如io已经成为了瓶颈,增加线程或许带来不了性能提升,这个时候是不是可以考虑用cpu换取带宽,压缩数据,或者逻辑上少发送一些。最后一个问题,我的答案是大部分应用环境是合理的,老师也说了是积累了一些调优经验后给出的方案,没有特殊需求,初始值我会选大家都在用伪标准

    作者回复: 👍👍

    2019-03-21
    5
    75
  • 多拉格·five
    问一下老师,这个线程配置比我在其他的资料也看过,但是最后那个公式没见过,方便说一下如何测试IO/CPU 这个耗时比例吗

    作者回复: 比较简单的工具就是apm了

    2019-03-21
    3
    53
  • aksonic
    早起的鸟果然有食吃,抢到了顶楼,哈哈。 对于老师的思考题,我觉得不合理,本来就是分CPU密集型和IO密集型的,尤其是IO密集型更是需要进行测试和分析而得到结果,差别很大,比如IO/CPU的比率很大,比如10倍,2核,较佳配置:2*(1+10)=22个线程,而2*CPU核数+1 = 5,这两个差别就很大了。老师,我说的对不对?

    作者回复: 不但起的早,还看懂了

    2019-03-21
    46
  • 董宗磊
    思考题:认为不合理,不能只考虑经验,还有根据是IO密集型或者是CPU密集型,具体问题具体分析。 看今天文章内容,分享个实际问题;我们公司服务器都是容器,一个物理机分出好多容器,有个哥们设置线程池数量直接就是:Runtime.getRuntime().availableProcessors() * 2;本来想获取容器的CPU数量 * 2,其实Runtime.getRuntime().availableProcessors()获取到的是物理机CPU合数,一下开启了好多线程 ^_^

    作者回复: 新版的jvm开始支持docker了,老版本问题还挺多

    2019-03-21
    2
    42
  • 南山
    理论加经验加实际场景,比如现在大多数公司的系统是以服务的形式来通过docker部署的,每个docker服务其实对应部署的就一个服务,这样的情况下是可以按照理论为基础,再加上实际情况来设置线程池大小的,当然通过各种监控来调整是最好的,但是实际情况是但服务几十上百,除非是核心功能,否则很难通过监控指标来调整线程池大小。理论加经验起码不会让设置跑偏太多,还有就是服务中的各种线程池统一管理是很有必要的

    作者回复: 说的太对了!!!

    2019-03-31
    31
  • 探索无止境
    老师早上好,当应用来的请数量过大,此时线程池的线程已经不够使用,排队的队列也已经满了,那么后面的请求就会被丢弃掉,如果这是一个更新数据的请求操作,那么就会出现数据更新丢失,老师有没有什么具体的解决思路?期待解答

    作者回复: 单机有瓶颈,就分布式。 数据库有瓶颈,就分库分表分片

    2019-03-21
    7
    18
  • 木卫六
    在4核8线程的处理器使用Runtime.availableProcessors()结果是8,超线程技术属于硬件层面上的并发,从cpu硬件来看是一个物理核心有两个逻辑核心,但因为缓存、执行资源等存在共享和竞争,所以两个核心并不能并行工作。超线程技术统计性能提升大概是30%左右,并不是100%。另外,不管设置成4还是8,现代操作系统层面的调度应该是按逻辑核心数,也就是8来调度的(除非禁用超线程技术)。所以我觉得这种情况下,严格来说,4和8都不一定是合适的,具体情况还是要根据应用性能和资源的使用情况进行调整。这是个人的理解,请老师指正。

    作者回复: 工作中都是按照逻辑核数来的,理论值和经验值只是提供个指导,实际上还是要靠压测。

    2019-03-22
    16
  • QQ怪
    我就想问下如何测试io耗时和cpu耗时

    作者回复: apm工具可以

    2019-03-21
    11
  • zsh0103
    请问老师, 1 在现实项目如何计算I/O耗时与CPU耗时呢,比如程序是读取网络数据,然后分析,最后插入数据库。这里网络读取何数据库插入是两次IO操作,计算IO耗时是两次的和吗? 2. 如果我在一台机器上部署2个服务,那计算线程数是要每个服务各占一半的数量吗? 3. 如果我用一个8核CPU的机器部署服务,启动8个不同端口的相同服务,和启动一个包含8个线程的服务在处理性能上会有区别吗?

    作者回复: 1.两次之和 2.理论值仅仅适用部署一个服务的场景。 3.有区别

    2019-03-21
    7
  • 已忘二
    老师,有个疑问,就是那个I/O和CPU比为2:1时,CPU使用率达到了100%,但是I/O使用率却到了200%,也就是时刻有两个I/O同时执行,这样是可以的么?I/O不需要等待的么?

    作者回复: io有瓶颈后,cpu使用率就上不去了

    2019-03-21
    10
    6
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部