多线程 - 如何合理配置线程池


总结

根据“任务的性质”分析

CPU 密集型任务

  • 和内存打交道,大量计算。例如大数的计算,正则匹配
  • 如何配置:
    • CPU 密集型任务应配置尽可能小的线程,如配置 Ncpu+1 个线程的线程池(Ncpu 是处理器的核的数目),这样留一个空出来,用来做切换。。
    • 如果线程太多,会造成线程在CPU内部的上下文切换。。CPU的线程上下文切换比指令执行耗时的更多。

IO 密集型任务

  • 解释:和磁盘,网络,文件,数据库交互很多的。
  • 如何配置:由于 IO 密集型任务线程并不是一直在执行任务,在操作的时间,是不消耗CPU的。不会经常在CPU内切换线程上下文,则应配置尽可能多的线程,如 2*Ncpu。
    • 对于 IO 型的任务的最佳线程数,有个公式可以计算 Nthreads = NCPU * UCPU * (1 + W/C)

      ❑NCPU 是处理器的核的数目

      ❑UCPU 是期望的 CPU 利用率(该值应该介于 0 和 1 之间)

      ❑W/C 是等待时间与计算时间的比率。等待时间与计算时间我们在 Linux 下使用相关的 vmstat 命令或者 top 命令查看。

混合型任务

  • 解释:前两者的混合
  • 如何配置:如果可以拆分,将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务。
    • 只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐 量将高于串行执行的吞吐量。
    • 如果这两个任务执行时间相差太大(例如:一个是常量时间,一个是正无穷),则没必要进行分解。
    • 可以通过 Runtime.getRuntime().availableProcessors()方法获得当前设备的 CPU 个数。

 

 

根据“任务的优先级”分析

优先级不同的任务可以使用优先级队列 PriorityBlockingQueue 来处理。它可 以让优先级高的任务先执行。

 

根据“任务的执行时间”分析

执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先 级队列,让执行时间短的任务先执行。

 

根据“任务的依赖性(依赖数据库连接)”分析

依赖数据库连接池的任务,因为线程􏰀交 SQL 后需要等待数据库返回结果, 等待的时间越长,则 CPU 空闲时间就越长,那么线程数应该设置得越大,这样 才能更好地利用 CPU。

 

建议使用有界队列

有界队列能增加系统的稳定性和预警能力,可以根据需 要设大一点儿,比如几千。

假设,我们现在有一个 Web 系统,里面使用了线程池来处理业务,在某些 情况下,系统里后台任务线程池的队列和线程池全满了,不断抛出抛弃任务的异 常,通过排查发现是数据库出现了问题,导致执行 SQL 变得非常缓慢,因为后台 任务线程池里的任务全是需要向数据库查询和插入数据的,所以导致线程池里的 工作线程全部阻塞,任务积压在线程池里。

如果当时我们设置成无界队列,那么线程池的队列就会越来越多,有可能会 撑满内存,导致整个系统不可用,而不只是后台任务出现问题。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM