Java 性能调优实战
刘超
前金山软件技术经理
58205 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
开篇词 (1讲)
模块一 · 概述 (2讲)
结束语 (1讲)
Java 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

18 | 如何设置线程池大小?

你好,我是刘超。
还记得我在 16 讲中说过“线程池的线程数量设置过多会导致线程竞争激烈”吗?今天再补一句,如果线程数量设置过少的话,还会导致系统无法充分利用计算机资源。那么如何设置才不会影响系统性能呢?
其实线程池的设置是有方法的,不是凭借简单的估算来决定的。今天我们就来看看究竟有哪些计算方法可以复用,线程池中各个参数之间又存在怎样的关系。

线程池原理

开始优化之前,我们先来看看线程池的实现原理,有助于你更好地理解后面的内容。
在 HotSpot VM 的线程模型中,Java 线程被一对一映射为内核线程。Java 在使用线程执行程序时,需要创建一个内核线程;当该 Java 线程被终止时,这个内核线程也会被回收。因此 Java 线程的创建与销毁将会消耗一定的计算机资源,从而增加系统的性能开销。
除此之外,大量创建线程同样会给系统带来性能问题,因为内存和 CPU 资源都将被线程抢占,如果处理不当,就会发生内存溢出、CPU 使用率超负荷等问题。
为了解决上述两类问题,Java 提供了线程池概念,对于频繁创建线程的业务场景,线程池可以创建固定的线程数量,并且在操作系统底层,轻量级进程将会把这些线程映射到内核。
线程池可以提高线程复用,又可以固定最大线程使用量,防止无限制地创建线程。当程序提交一个任务需要一个线程时,会去线程池中查找是否有空闲的线程,若有,则直接使用线程池中的线程工作,若没有,会去判断当前已创建的线程数量是否超过最大线程数量,如未超过,则创建新线程,如已超过,则进行排队等待或者直接抛出异常。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(63)

  • 最新
  • 精选
  • 你好旅行者
    老师好!关于线程池我有一个问题一直不明白,在线程池达到了核心线程数,等待队列没满的这段时间,新的任务会被加入到等待队列。而当等待队列满了之后,最大线程数没满的这段时间,线程池会为新的任务直接创建线程。那岂不是说,我后来的任务反而比先到的任务更早被分配到线程的资源?这是不是有点不太合理呢?

    作者回复: 对的,如果队列满了,就会新增线程来执行任务,如果已经是最大线程数量,则会执行拒绝策略。 这里不应该说不合理,而是不公平。可以深入源码查看具体的实现。

    8
    35
  • 明翼
    老师早点发这个课就好了,先回答问题:程序的总体时间是由所有部分加起来时间决定的,串行如果很慢就会严重影响性能,优化是从性能最差的地方开始的。 请教问题: 1)按照老师的图,如果线程没超过核心线程,就创建,超过则加入到队列,队列满又没达到最大线程则创建非核心线程,那么创建好的线程是直接执行最近来的任务那,还是从队列的头部取一个执行。 2)第二个问题,如果线程池的线程数的在核心线程数量之内,A线程执行刚执行完任务,这时候来了个新来的任务a,那么这个A线程继续执行这个新来任务a,还是其他线程执行这个线程那,这里面有什么分配策略

    作者回复: 1、如果队列满了,这个现成的任务会创建非核心线程,也就是不会先运行队列中的任务。 2、新来的任务a会通过创建新的线程来运行,只要线程数量小于核心线程数,新来的任务都会通过创建新的线程来运行。直到等于核心线程数,任务将会放到阻塞队列中,通过循环拿到阻塞队列中的任务执行。

    17
  • 阿杜
    线程池核心线程数的设置多少不仅仅依赖cpu核数和执行时间,还有线程执行的资源,比如调用的db,db连接数有限,线程数太多就可能打满db连接。

    作者回复: 赞,做性能压测的时候会经常遇到这种情况,当某条SQL比较耗时的时候,如果线程数设置过大,就会出现不能打开DB连接的异常。

    3
    16
  • 飞翔
    话说N+1和2N 是指的核心线程数嘛? 那队列和最大线程数怎么设置呀

    作者回复: 在一些非核心业务,我们可以将核心线程数设置小一些,最大线程数量设置为计算线程数量。在一些核心业务中,两者可以设置一样。阻塞队列可以根据具体业务场景设置,如果线程处理业务非常迅速,我们可以考虑将阻塞队列设置大一些,处理的请求吞吐量会大些;如果线程处理业务非常耗时,阻塞队列设置小些,防止请求在阻塞队列中等待过长时间而导致请求已超时。

    16
  • nico
    老师,请教个问题,生产环境有些应用是混部的,即一个虚拟机上跑很多个java程序,这个时候估算一个程序中的线程池的线程数,是不是就不合理了?这个要怎么估算合理的线程池配置?还有就是即使是单实例部署,cpu资源是机器内共用的,不可能只分配给java线程,这个要怎么考虑?

    作者回复: 我们先考虑单个环境,再去调优复杂环境。大多情况下,重要的服务会单独部署,尽量减少重要业务的相互影响。如果是核心业务冗余在了一个服务上,建议拆分之后分别部署。 非核心业务,很多业务处理可能是在不同时间点,彼此相互不影响,所以不用过多考虑混合部署服务的情况。

    2
    12
  • Jxin
    1.能理解io操作不占用cpu计算,但是io线程依旧不会让渡cpu资源的(执行时间片)。所以io线程池独立和调整io线程数只是因为它耗时不确定,一般耗时较长的特性。 2.综上所述,那么线程池线程数基本就20-30的样子(而且这个值怎么感觉是多个线程池的线程总数呢)。那么tomcat线程池默认好像200条吧,dubbo线程池我们设置1000条线程,这是否就不合理了?(线程这块太水,麻烦老师解惑下)

    作者回复: 我们一般会调整tomcat的线程数量的,线上环境的tomcat线程数量我们一般是在16核CPU的环境下为20左右。如果有万级的并发过来,100以及1000的线程数量,可能会有问题。

    5
    9
  • K
    老师好,我也是看了下边同学的评论,又学到了很多知识。我有一个地方不理解,线程如果读文件的时候,这个线程可能处于wait的状态,然后cpu就可以被其他线程拿到使用了。那为什么看到有同学说:“io操作不占用cpu计算,但是io线程依旧不会让渡cpu资源的(执行时间片)”。麻烦老师解答一下,谢谢老师。

    作者回复: 这里理解是有误差的,目前很多服务器的IO操作都是交给DMA去完成,所以这里是让出CPU资源的。

    8
  • 许童童
    优化并行操作是不是优化系统的关键呢? 可以参考阿姆达尔定律 S=1/(1-a+a/n) 总之,优化并行操作带来的收益是有上限的。

    作者回复: 赞,Amdahl's定律指出优化串行是优化系统性能的关键,我们应该从算法入手,减少程序中串行的部分,而不是增加线程数来提高系统的并发处理能力。

    2
    8
  • Liam
    请教老师一个问题: 对于应用而言,可能有多种类型的任务要执行,我们是分别创建不同的线程池还是创建一个统一的线程池来控制资源的使用呢? 1 如果用一个统一的线程池,担心io任务占有太多线程导致其他任务没有足够的线程消费 2 如果用多个线程池,这个资源怎么管理,会不会导致整个应用的线程数量过多,引起太多上下文切换从而导致开销过大

    作者回复: 分别创建。 如果过分彼此相互影响,建议拆开服务,分别部署。

    7
  • 承香墨影
    只有在 workQueue 满了之后才会创建新的线程,直到线程数到达 maximumPoolSize 值。所以这里的等待队列无法使用无界队列就会导致永远都用不上 maximumPoolSize。当我们自己指定 ThreadPoolExecutor 参数的时候,需要注意不要使用无界队列,或者使用无界队列让 corePoolSize 和 maximumPoolSize 保持一致也可以。 参考:newFixedThreadPool 的创建过程。

    作者回复: 赞

    6
收起评论
显示
设置
留言
63
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部