那是一个风和日丽的下午!java
面试官微微一笑,对我说:“小伙子,合理配置线程池你是如何考虑的?”面试
我微微一笑,说出了个人答案:算法
首先确认业务是CPU密集型仍是IO密集型的,数据库
若是是CPU密集型的,那么就应该尽可能少的线程数量,通常为CPU的核数+1;编程
若是是IO密集型:因此可多分配一点 cpu核数*2 也可使用公式:CPU 核数 / (1 - 阻塞系数);其中阻塞系数在 0.8 ~ 0.9 之间。服务器
面试官心想,有点东西,接着追问:“那你是如何获得的这个公式,或者说你是如何根据CPU核心数肯定线程池并发线程数的”网络
我心想这不是小瞧我嘛?不屑回答的我脱下了个人帽子并发
哈哈哈哈,进入正题!测试
关于如何计算并发的线程数量,通常分两派,来自两本书,且都是好书,线程
第一派:《Java Concurrency in Practice》即《java并发编程实践》,咱们简称A派。
第二派:《Programming Concurrency on the JVM Mastering》即《Java 虚拟机并发编程》,咱们简称B派。
到底哪一个是对的?咱们截取书中部份内容具体看看。
A派一书中是这样写的
B派一书中是这样写的
对于A派,假设CPU跑满,即撇开CPU使用率这个因素,A派认为 线程数 = Ncpu * ( 1 + w/c )
大胆假设将B派的公式等于A派公式,
即 Ncpu / (1-阻塞系数) = Ncpu * ( 1 + w/c ) 即 阻塞系数 = 阻塞时间 /(阻塞时间+计算时间),
这个结论在派系二后续中获得应征,以下图:
那么实际使用中并发线程数如何设置呢?分析以下(咱们以A派公式为例):
Nthreads = Ncpu * (1+w/c)
IO密集型:通常状况下,若是存在IO,那么确定w/c>1(阻塞耗时通常都是计算耗时的不少倍),可是须要考虑系统内存有限(每开启一个线程都须要内存空间),这里须要上服务器测试具体多少个线程数适合(CPU占比、线程数、总耗时、内存消耗)。
若是不想去测试,保守点取1即,Nthreads=Ncpu*(1+1)=2Ncpu。这样设置通常都OK。
CPU密集型: 假设没有等待w=0,则W/C=0. Nthreads=Ncpu。
再次概括下:
IO密集型 = 2Ncpu(能够测试后本身控制大小,2Ncpu通常没问题)(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)
CPU密集型 = Ncpu(常出现于线程中:复杂算法)
java中:Ncpu = Runtime.getRuntime().availableProcessors()
A派的另外一个说法
即对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,一般能实现最优的效率。(即便当计算密集型的线程偶尔因为缺失故障或者其余缘由而暂停时,这个额外的线程也能确保CPU的时钟周期不会被浪费。)
即,计算密集型=Ncpu+1,可是这种作法致使的多一个cpu上下文切换是否值得,这里不考虑。读者可本身考量。
本文借鉴概括:Flag Counter 《根据CPU核心数肯定线程池并发线程数》