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

    作者回复: 对的,如果队列满了,就会新增线程来执行任务,如果已经是最大线程数量,则会执行拒绝策略。

    这里不应该说不合理,而是不公平。可以深入源码查看具体的实现。

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

    作者回复: 我们先考虑单个环境,再去调优复杂环境。大多情况下,重要的服务会单独部署,尽量减少重要业务的相互影响。如果是核心业务冗余在了一个服务上,建议拆分之后分别部署。

    非核心业务,很多业务处理可能是在不同时间点,彼此相互不影响,所以不用过多考虑混合部署服务的情况。

    
     6
  • 明翼
    2019-07-02
    老师早点发这个课就好了,先回答问题:程序的总体时间是由所有部分加起来时间决定的,串行如果很慢就会严重影响性能,优化是从性能最差的地方开始的。

    请教问题:
    1)按照老师的图,如果线程没超过核心线程,就创建,超过则加入到队列,队列满又没达到最大线程则创建非核心线程,那么创建好的线程是直接执行最近来的任务那,还是从队列的头部取一个执行。
    2)第二个问题,如果线程池的线程数的在核心线程数量之内,A线程执行刚执行完任务,这时候来了个新来的任务a,那么这个A线程继续执行这个新来任务a,还是其他线程执行这个线程那,这里面有什么分配策略
    展开

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

    
     5
  • QQ怪
    2019-06-29
    老师,我想问下生产环境情况下很少碰到单个java进程在一台主机中运行,大部分肯定是多个进程同时运行,不如docker技术,都是共享同一套硬件,那这套计算方程式是不是不适用了?

    作者回复: 适用的,多个进程大部分时间不一定是重合运行的。但具体情况需要具体定,所以最终还是以压测调出来的线程数为准。

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

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

    
     4
  • 飞翔
    2019-06-30
    话说N+1和2N 是指的核心线程数嘛? 那队列和最大线程数怎么设置呀

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

    
     3
  • Liam
    2019-06-29
    请教老师一个问题:

    对于应用而言,可能有多种类型的任务要执行,我们是分别创建不同的线程池还是创建一个统一的线程池来控制资源的使用呢?

    1 如果用一个统一的线程池,担心io任务占有太多线程导致其他任务没有足够的线程消费

    2 如果用多个线程池,这个资源怎么管理,会不会导致整个应用的线程数量过多,引起太多上下文切换从而导致开销过大
    展开

    作者回复: 分别创建。

    如果过分彼此相互影响,建议拆开服务,分别部署。

    
     2
  • 张学磊
    2019-06-29
    老师,线程池流程图提交任务后的第一个节点应该是线程数是否大于核心线程数,如果是再判断队列是否已满,否则直接创建新线程。

    思考题,个人觉得线性执行的代码会成为影响性能的关键,应尽量减少执行时间,比如减少锁持有时间,这样才能达到最大程度的并发。

    作者回复: 感谢学磊童鞋的提醒,已修正。

    答案正确!

    
     2
  • chp
    2020-01-09
    有个问题是,任务既有CPU消耗,也有IO消耗,这种情况下要用哪个公式好?

    作者回复: io为主,通常我们都是设置2*n,例如netty中的io线程池的线程数量默认为2*n

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

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

    
    
  • 杨彬Lennon
    2019-11-13
    线程池的线程分配流程,这个图不对吧?队列是否已满:是的话要执行拒绝策略,否的话要加入任务队列,等待释放的线程资源。不知道是不是这样?

    作者回复: 这个流程图没问题的,在队列满了之后,还会去判断线程池是否能再新增非核心线程,我们具体可以深入源码熟悉线程池的工作原理。

     1
    
  • Demon.Lee
    2019-10-24
    老师,如果线程池没有达到核心线程数,等待队列中也没有数据(即空),那么新来的任务也会创建新的线程执行么,还是用池中原有的线程执行?看流程图突然想到了这个问题

    作者回复: 没有到达核心线程数,新的任务进来也会创建线程执行,可以查看源码看到具体的实现

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

    作者回复: 赞

    
    
  • 雪梨
    2019-09-21
    老师,集群部署的情况,集群有8台机器,按这说法,cpu密集型任务,也要按单机的核数+1么?

    作者回复: 一般是按单机来算线程数

    
    
  • 雪梨
    2019-09-21
    老师,cpu密集型任务,集群部署的情况,集群有8台机器,按这个N+1说法,怎么配呢?集群会影响配这个值么?
    
    
  • 疯狂咸鱼
    2019-09-21
    老师,最后一段表述是不是有问题,"将来不及处理的线程缓存到队列中",应该是任务吧

    作者回复: 对的

    
    
  • 疯狂咸鱼
    2019-09-21
    老师,平时常听到的4核8线程是什么意思?在cpu密集情况下,线程数是4+1还是8+1?

    作者回复: cpu密集情况下是n+1,如果是4核的情况下就是4+1。2n+1一般用于io密集的情况

    
    
  • 疯狂咸鱼
    2019-09-21
    老师讲课的逻辑思路真清楚,可见功力之强、知识体系完整。每天看一遍都有新的收获
    
    
  • godtrue
    2019-09-10
    课后思考及问题
    1:当程序提交一个任务需要一个线程时,会去线程池中查找是否有空闲的线程,若有,则直接使用线程池中的线程工作,若没有,会去判断当前已创建的线程数量是否超过最大线程数量,如未超过,则创建新线程,如已超过,则进行排队等待或者直接抛出异常。
    我们可以通过下面这张图来了解下线程池的线程分配流程:
    有个疑问,感觉上段文字描述和线程池的分配流程不符?请老师解释下那个更加准确,我也看到评论区有好多同学都有这样的疑惑。老师的解释是线程池的分配流程图是OK的,假如线程池的分配流程图是OK的,那请老师解释一下如下疑问:
    1:为什么会与上面这段文字的描述不符?
    2:是否意味着等待队列中的任务只会分配给,核心线程?
    3:老师后文又提到销毁线程时核心线程和非核心线程是同等对待的,这与2中的推断又是矛盾的?
    4:假如老师解释清楚了1/2/3,这三个矛盾点,那我想问一下线程池的分配流程为什么这么设计?
    5:线程池各个参数的相互关系图,我仔细看了几遍,有一个小瑕疵——corePoolSize那个位置也属于核心线程应该占的位置吧?图中核心线程有7个位置,非核心线程有6个位置,任务等待队列有9个位置,按照老师的线程池分配流程图来看,第1~6个线程提交的任务有核心线程来处理,第7~15个线程提交的任务会放入任务等待队列,第16~22个线程提交的任务会有非核心线程来处理(假设理想情况下这样)
    5-1:此时再来一个线程提交的任务会根据拒绝策略来处理?全面的拒绝策略有几种都是如何实现的?
    5-2:假如核心线程1处理完了一个任务,它去任务等待队列中获取任务是从队头有序获取的嘛?
    5-3:会存在核心线程处理完任务重新放入线程池比新提交的任务晚,导致任务被拒绝的场景吧?这个有什么解决思路嘛?
    5-4:如果只有15个线程提交任务,非核心线程是永远都不会创建了吧?
    5-5:核心线程和非核心线程,本身或者在线程池中区分不开,所以,销毁时才不做区分同等对待嘛?
    问题有点多,望老师解惑!
    展开
    
    
  • Demon.Lee
    2019-08-30
    老师,两个测试例子,一开始线程数都是2的时候,线程整体运行时间都很高,是不是因为此时线程池里面还没有线程,创建线程需要时间?

    作者回复: 是的,需要初始化

    
    
我们在线,来聊聊吧