我们在使用线程池的时候,会有两个疑问点: 线程池的线程数量设置过多会导致线程竞争激烈 如果线程数量设置过少的话,还会导致系统无法充分利用计算机资源 那么如何设置才不会影响系统性能呢? 不过我不太推荐使用它们,因为选择使用 Executors 提供的工厂类,将会忽略很多线程池的参数设置,工厂类一旦选择设置默认参数,就很容易导致无法调优参数设置,从而产生性能问题或者资源浪费。 通过上图,我们发现线程池有两个线程数的设置,一个为核心线程数,一个为最大线程数。在创建完线程池之后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务。 我们可以通过下面这张图来了解下线程池的线程分配流程: ? 计算线程数量 了解完线程池的实现原理和框架,我们就可以动手实践优化线程池的设置了。 :" + (end - start)); } } 备注:由于测试代码读取 2MB 大小的文件,涉及到大内存,所以在运行之前,我们需要调整 JVM 的堆内存空间:-Xms4g -Xmx4g,避免发生频繁的
要想合理的配置线程池的大小,首先得分析任务的特性,可以从以下几个角度分析: 任务的性质:CPU密集型任务、IO密集型任务、混合型任务。 任务的优先级:高、中、低。 任务的执行时间:长、中、短。 当然具体合理线程池值大小,需要结合系统实际情况,在大量的尝试下比较才能得出,以上只是前人总结的规律。 在这篇如何合理地估算线程池大小? 线程CPU时间所占比例越高,需要越少线程。 以上公式与之前的CPU和IO密集型任务设置线程数基本吻合。 并发编程网上的一个问题 高并发、任务执行时间短的业务怎样使用线程池? )一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换 (3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步 ,至于线程池的设置,设置参考(2)。
线程池大小的设置策略 线程池需要设置合适的大小,假如设置的太大,线程上线文切换过于频繁,造成大量资源开销,反而会使性能降低。 假如设置的太小,存在很多可用的处理器资源却未在工作,会造成资源的浪费和对吞吐量造成损失。 为了充分利用处理器资源,创建的线程数至少要等于处理器核心数。 如果所有的任务都是计算密集型的,那么线程数等于可用的处理器核心数就可以了。不过,如果所有的任务都是IO密集型,那么处理器大部分时间是空闲的,所有要适当的增加线程数。 线程等待时间所占比例越高,需要越多线程。线程运算时间所占比例越高,需要越少线程。 于是可以使用下面的公式进行估算: 最佳线程数 = (1 + 线程等待时间/线程计算时间)* 目标CPU的使用率 * 处理器核心数 例如:平均每个线程计算运行时间为0.5s,而线程等待时间(非计算时间,比如
如何合理设置Java线程池大小:依据任务类型定制策略 Java线程池的合理配置直接关系到系统性能和资源利用率。 根据任务性质的不同,合理的线程池大小设置策略也有所区别,主要包括CPU密集型、IO密集型及混合型任务。 1. 设置策略:线程池大小建议设置为CPU核心数+1。因为对于CPU密集型任务,增加线程数量并不能提高执行效率,反而可能导致线程上下文切换的额外开销,降低系统性能。 设置策略: 方法一:推荐线程池大小设置为CPU核心数*2。由于I/O操作不占用CPU,增加线程可以让CPU在等待I/O时处理其他任务,提升CPU利用率。 如果拆分困难,可以评估任务中CPU和I/O操作的比例,折中选取一个相对平衡的线程池大小。 总之,合理设置线程池大小的核心在于理解任务特性,通过科学的计算和经验调整,使系统达到资源利用与性能的最佳平衡。
可能很多人都看到过一个线程数设置的理论: CPU 密集型的程序 - 核心数 + 1 I/O 密集型的程序 - 核心数 * 2 不会吧,不会吧,真的有人按照这个理论规划线程数? 真实程序中的线程数 那么在实际的程序中,或者说一些Java的业务系统中,线程数(线程池大小)规划多少合适呢? 默认Tomcat容器+HikariCP连接池+G1回收器,如果此时项目中也需要一个业务场景的多线程(或者线程池)来异步/并行执行业务流程。 因为此时这台主机上,已经有很多运行中的线程了,Tomcat有自己的线程池,HikariCP也有自己的后台线程,JVM也有一些编译的线程,连G1都有自己的后台线程。 (池)的区分,I/O线程一般不是瓶颈,所以不必太多,但业务线程很容易称为瓶颈 Redis 6.0以后也是多线程了,不过它只是I/O 多线程,“业务”处理还是单线程 所以,不要纠结设置多少线程了。
那么在用到并发功能的过程中,就肯定会碰到下面这个问题 并发线程池到底设置多大呢? 通常有点年纪的程序员或许都听说这样一个说法 (其中 N 代表 CPU 的个数) CPU 密集型应用,线程池大小设置为 N + 1 IO 密集型应用,线程池大小设置为 2N 这个说法到底是不是正确的呢? 因为线程池的大小只能服务器的核数有关,所以这个说法是不正确的。那具体应该怎么设置大小呢? 假设这个应用是两者混合型的,其中任务即有 CPU 密集,也有 IO 密集型的,那么我们改怎么设置呢? 那么我们到底该怎么设置线程池大小呢?有没有一些具体实践方法来指导大家落地呢?让我们来深入地了解一下。 CPU 个数 cat /proc/cpuinfo| grep "processor"| wc -l 总结 合适的配置线程池大小其实很不容易,但是通过上述的公式和具体代码,我们就能快速、落地的算出这个线程池该设置的多大
那么在用到并发功能的过程中,就肯定会碰到下面这个问题 并发线程池到底设置多大呢? 通常有点年纪的程序员或许都听说这样一个说法 (其中 N 代表 CPU 的个数) CPU 密集型应用,线程池大小设置为 N + 1 IO 密集型应用,线程池大小设置为 2N 这个说法到底是不是正确的呢? 因为线程池的大小只能服务器的核数有关,所以这个说法是不正确的。那具体应该怎么设置大小呢? 假设这个应用是两者混合型的,其中任务即有 CPU 密集,也有 IO 密集型的,那么我们改怎么设置呢? 那么我们到底该怎么设置线程池大小呢?有没有一些具体实践方法来指导大家落地呢?让我们来深入地了解一下。 CPU 个数 cat /proc/cpuinfo| grep "processor"| wc -l 总结 合适的配置线程池大小其实很不容易,但是通过上述的公式和具体代码,我们就能快速、落地的算出这个线程池该设置的多大
我们在使用线程池的时候,会有两个疑问点: 线程池的线程数量设置过多会导致线程竞争激烈 如果线程数量设置过少的话,还会导致系统无法充分利用计算机资源 那么如何设置才不会影响系统性能呢? 不过我不太推荐使用它们,因为选择使用 Executors 提供的工厂类,将会忽略很多线程池的参数设置,工厂类一旦选择设置默认参数,就很容易导致无法调优参数设置,从而产生性能问题或者资源浪费。 通过上图,我们发现线程池有两个线程数的设置,一个为核心线程数,一个为最大线程数。在创建完线程池之后,默认情况下,线程池中并没有任何线程,等到有任务来才创建线程去执行任务。 我们可以通过下面这张图来了解下线程池的线程分配流程: ? 计算线程数量 了解完线程池的实现原理和框架,我们就可以动手实践优化线程池的设置了。 :" + (end - start)); } } 备注:由于测试代码读取 2MB 大小的文件,涉及到大内存,所以在运行之前,我们需要调整 JVM 的堆内存空间:-Xms4g -Xmx4g,避免发生频繁的
Java线程池的大小与线程池死锁 优化线程池大小 线程池大小对系统性能是有一定影响的,过大或者过小都会无法发挥最优的系统性能, 线程池大小不需要非常精确,只要避免极大或者极小的情况即可, 一般来说,线程池大小需要考虑 CPU数量,内存大小等因素. 在书中给出一个估算线程池大小的公式: 线程池大小 = CPU的数量 * 目标CPU的使用率*( 1 + 等待时间与计算时间的比) 线程池死锁 如果在线程池中执行的任务A在执行过程中又向线程池提交了任务B 适合给线程池提交相互独立的任务,而不是彼此依赖的任务. 对于彼此依赖的任务,可以考虑分别提交给不同的线程池来执行。 Java线程池异常处理 在使用ThreadPoolExecutor进行submit提交任务时,有的任务抛出了异常,但是线程池并没有进行提示,即线程池把任务中的异常给吃掉了,可以把submit提交改为execute
二:线程池参数 ThreadPoolExecutor类可设置的参数主要有: corePoolSize:核心线程 1.核心线程会一直存活,及时没有任务需要执行 2.当线程数小于核心线程数时,即使有线程空闲 ,线程池也会优先创建新线程处理 3.设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭 一:queueCapacity:任务队列容量(阻塞队列) 当核心线程数达到最大时 线程池会创建新线程来处理任务 2.当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常 keepAliveTime:线程空闲时间 1.当线程空闲时间达到keepAliveTime 3.当线程数大于等于核心线程数,且任务队列已满 3.1若线程数小于最大线程数,创建线程 3.2若线程数等于最大线程数,抛出异常,拒绝任务 三:线程池参数的合理设置 为了说明合理设置的条件,我们首先确定有以下几个相关参数 若结合CPU的情况,比如,当线程数量达到50时,CPU达到100%,则将maxPoolSize设置为60也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法降低每个任务的处理时间
那么在用到并发功能的过程中,就肯定会碰到下面这个问题 并发线程池到底设置多大呢? 通常有点年纪的程序员或许都听说这样一个说法 (其中 N 代表 CPU 的个数) CPU 密集型应用,线程池大小设置为 N + 1 IO 密集型应用,线程池大小设置为 2N 这个说法到底是不是正确的呢? 因为线程池的大小只能服务器的核数有关,所以这个说法是不正确的。那具体应该怎么设置大小呢? 假设这个应用是两者混合型的,其中任务即有 CPU 密集,也有 IO 密集型的,那么我们改怎么设置呢? 那么我们到底该怎么设置线程池大小呢?有没有一些具体实践方法来指导大家落地呢?让我们来深入地了解一下。 Little's Law(利特尔法则) ? CPU 个数 cat /proc/cpuinfo| grep "processor"| wc -l 总结 合适的配置线程池大小其实很不容易,但是通过上述的公式和具体代码,我们就能快速、落地的算出这个线程池该设置的多大
那么在用到并发功能的过程中,就肯定会碰到下面这个问题 并发线程池到底设置多大呢? 通常有点年纪的程序员或许都听说这样一个说法 (其中 N 代表 CPU 的个数) CPU 密集型应用,线程池大小设置为 N + 1 IO 密集型应用,线程池大小设置为 2N 这个说法到底是不是正确的呢? 因为线程池的大小只能服务器的核数有关,所以这个说法是不正确的。那具体应该怎么设置大小呢? 假设这个应用是两者混合型的,其中任务即有 CPU 密集,也有 IO 密集型的,那么我们改怎么设置呢? 那么我们到底该怎么设置线程池大小呢?有没有一些具体实践方法来指导大家落地呢?让我们来深入地了解一下。 Little's Law(利特尔法则) ? CPU 个数 cat /proc/cpuinfo| grep "processor"| wc -l 总结 合适的配置线程池大小其实很不容易,但是通过上述的公式和具体代码,我们就能快速、落地的算出这个线程池该设置的多大
线程池的参数应该怎样设置呢?相信对于很多的人来说这也是一个比较难的问题,下面就让我们一起来解决一下,究竟应该如何设置线程池的参数才是最合理的吧! 1、下游系统抗并发的能力 多线程给下游系统造成的并发等于你设置的线程数 例: 假如,是多线程访问数据库,那么就得考虑数据库的连接池大小设置,数据库并发太多影响其qps,会将数据库打挂等问题。 3、线程池中执行的任务性质 计算密集型的任务比较占cpu,所以说,通常线程数设置的大小等于或者是略微大于cpu的核数。 队列的大小应该通过前期计算线程池任务的条数,来合理的设置队列的大小,不适合太小,让它不会溢出,因为,溢出会走拒绝策略,多多少少对于它的性能会造成一定的影响,与此同时,复杂度也会被增加,所以,这里需要我们好好的考量拒绝策略的选择 以上就是对于线程池参数设置的一个简单介绍了,你都了解了吗?更多内容,请继续关注奇Q工具网的常见问题栏目了解吧。
本文由杨青同学投稿,总结了他在近期工作中对线程池容量设置的一点经验。 原文发于微信公众号:Java线程池容量设置 创建线程池的方式 Java中可以通过Executors和ThreadPoolExecutor的方式创建线程池,通过Executors可以快速创建四种常见的线程池 corePoolSize设置是整个线程池中最关键的参数,设置太小会导致线程池的吞吐量不足,因为新提交的任务需要排队或者被handler处理掉(取决于拒绝策略);设置太大可能会耗尽计算机的CPU和内存资源 在压测的过程中发现,当线程数量设置的更合理时TPS更高且接口的RT较低;而线程池设置过大导致TPS下降和RT上涨。由于RT和TPS不太方便直接给出,这里仅展示系统负载这一指标的压测结果。 当线程池设置过大时: ? 图2 压测时把线程池参数设置得很大 当线程池设置较为合理时: ?
如何确定线程池大小? 线程数不是越多越好。 由于CPU的核心数有限,线程之间切换也需要开销,频繁的切换上下文会使性能降低,适得其反。 简单的总结就是: Ncpu 表示 核心数。 在《Java并发编程实践》中,是这样来计算线程池的线程数目的: 一个基准负载下,使用 几种不同大小的线程池运行你的应用程序,并观察CPU利用率的水平。 如果线程池中的线程在执行任务时,密集计算所占的时间比重为P(0<P<=1),而系统一共有C个CPU,为了让CPU跑满而又不过载,线程池的大小经验公式 T = C / P。 : https://blog.csdn.net/youanyyou/article/details/78990156 《java虚拟机并发编程》 腾讯面试官:线程池要设置多大: http:/ /www.zyiz.net/tech/detail-121726.html 如何合理地估算线程池大小?
我们如果使用Java语言的话,我们来分析一下Java线程池。 Java中的ThreadPoolExecutor 理论上线程池的参数设置情况 ? 理论必定只是理论,到真实的场景中我们的目的性是不一样的。 所以在设置线程池的时候我们还是确定一个最后权重比较大的目标去设置。 线程池的目的我们也知道了,大概设置的基础理论也清楚了。看看美团技术团队给的两个场景。 另外,使用线程池也是有考量的,这种场景最重要的就是获取最大的响应速度去满足用户,所以应该不设置队列去缓冲并发任务,调高corePoolSize和maxPoolSize去尽可能创造多的线程快速执行任务。 个大小容量的队列。然后避过这个高峰我们的线程继续去消费。但是在我们目前这种场景是不设置队列的。设置位0,因为用户对等待是零容忍的。 快速处理批量任务 描述:离线的大量计算任务,需要快速执行。 总结 线程池的作用 线程池理论参数设置参考 场景分析 参考 美团技术团队-Java线程池实现原理及其在美团业务中的实践
为了减轻这些开销,引入了线程池的概念。 在本文中,我们深入探讨确定理想线程池大小的艺术。一个经过精心调整的线程池可以从系统中提取出最佳性能,并帮助你在高峰工作负载中优雅地导航。 2 设置线程池大小:了解系统和资源限制 在确定线程池大小时,了解系统的限制,包括硬件和外部依赖项,是至关重要的。 CPU核心:确定服务器上可用的CPU核心数量对于优化线程池大小至关重要。 创建线程池:创建一个线程池,其大小接近或略小于可用CPU核心数。在这种情况下,你可能选择6或7个线程,以为其他任务和系统进程留出一些CPU容量。 创建线程池:创建一个线程池,其大小在并行性与预期的I/O延迟之间取得平衡。你不一定需要每个任务一个线程;相反,你可以拥有一个较小的池,有效地管理I/O密集型任务。
来源:蒋小强 , ifeve.com/how-to-calculate-threadpool-size/ 如何合理地估算线程池大小? 这个问题虽然看起来很小,却并不那么容易回答。 那么问题转化为: 如何设计线程池大小,使得可以在1s内处理完20个Transaction? 再来第二种简单的但不知是否可行的方法(N为CPU总核数): 如果是CPU密集型应用,则线程池大小设置为N+1 如果是IO密集型应用,则线程池大小设置为2N+1 如果一台服务器上只部署这一个应用并且只有这一个线程池 是否使用线程池就一定比使用单线程高效呢? 答案是否定的,比如Redis就是单线程的,但它却非常高效,基本操作都能达到十万量级/s。 我可以如下构造一个线程池: ThreadPoolExecutor pool = new ThreadPoolExecutor(256, 256, 0L, TimeUnit.MILLISECONDS,
参数说明 corePoolSize:核心线程数大小,不管它们创建以后是不是空闲的。 线程池需要保持 corePoolSize 数量的线程,除非设置了 allowCoreThreadTimeOut; maximumPoolSize:最大线程数,线程池中最多允许创建 maximumPoolSize workQueue:存放待执行任务的队列:当提交的任务数超过核心线程数大小后,再提交的任务就存放在这里。 线程池有5种状态,按大小排序如下:RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED private static final int RUNNING 其实可以把二者设置为相同的值,然后设置allowCoreThreadTimeOut 参数设置为 true ,核心线程在空闲了 keepAliveTime 的时间后也会被回收的,相当于线程池自动给你动态修改
线程池的长度取决于未来提交的任务类型和所部署的系统特征。 概述 制定线程池的长度并不是一门精密的科学,需要做的仅仅是避免“过大”和“过小”者两个极端情况。 如果一个线程池过大,那么线程对稀缺的CPU和内存资源的竞争,会导致内存的高使用量,还可能耗尽资源。如果过小,由于存在很多可用的处理器资源却未在工作,会对吞吐量造成损失。 如果有不同类别的任务,它们拥有差别很大很为,那么可以考虑使用多个线程池,这样每个线程池可以根据不同任务的工作负载进行调节。 估算 一般说来,大家认为线程池的大小经验值应该这样设置:(其中N为CPU的个数) 如果是CPU密集型应用,则线程池大小设置为N+1 如果是IO密集型应用,则线程池大小设置为2N+1 如果一台服务器上只部署这一个应用并且只有这一个线程池 这个公式进一步转化为: 最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目 刚刚说到的线程池大小的经验值,其实是这种公式的一种估算值。 参考 如何合理地估算线程池大小?