JAVA并发梳理(五)线程池

关于线程池的实现,各自的特点等稍后再补充。
现在先总结下如何合理地设置线程池的大小。

线程池中线程的数目是跟线程池所要处理的任务性质有关的

  • 任务的性质:CPU密集型任务、IO密集型任务、混合型任务。
  • 任务的优先级:高、中、低。
  • 任务的执行时间:长、中、短。
  • 任务的依赖性:是否依赖其他系统资源,如数据库连接等。

性质不同的任务可以交给不同规模的线程池执行

针对不同的任务性质而言:

  • CPU密集型任务应配置尽可能小的线程,如配置CPU个数+1的线程数
  • IO密集型任务应配置尽可能多的线程,因为IO操作不占用CPU,不要让CPU闲下来,应加大线程数量,如配置2*CPU个数+1
  • 对于混合型的任务,如果可以拆分,拆分成IO密集型和CPU密集型分别处理,前提是两者运行的时间是差不多的,如果处理时间相差很大,则没必要拆分了。

任务对其他系统资源有依赖
如某个任务依赖数据库的连接返回的结果,这时候等待的时间越长,则CPU空闲的时间越长,那么线程数量应设置得越大,才能更好的利用CPU。

线程等待时间所占比例越高,这样的话CPU空闲时间比较多,为了能够更好的利用CPU,需要较多线程。

最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目 

如果线程CPU时间所占比例越高,说明CPU比较繁忙,此时需要越少线程。
另外,如果线程数量过多,线程之间的切换也会带来开销。

根据短板效应,真实的系统吞吐量并不能单纯根据CPU来计算。要提高系统吞吐量,就需要从“系统短板”(比如网络延迟、IO)着手。

尽量提高短板操作的并行化比率,比如多线程下载技术
增强短板能力,比如用NIO替代IO

是否使用线程池就一定比使用单线程高效呢?
答案是否定的,比如Redis就是单线程的,但它却非常高效,基本操作都能达到十万量级/s。从线程这个角度来看,部分原因在于:多线程带来线程上下文切换开销,单线程就没有这种开销。

来自并发编程网上的一个问题:
高并发、任务执行时间短的业务怎样使用线程池?
并发不高、任务执行时间长的业务怎样使用线程池?
并发高、业务执行时间长的业务怎样使用线程池?
(1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
(2)并发不高、任务执行时间长的业务要区分开看:
  a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务
  b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换
(3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。

引用
并发下线程池的最佳数量计算
如何合理设置线程池大小
线程池中如何确定线程的数目

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。