提到线程池的数量,也许我们能想到通过java相关的api,比如ThreadPollExecutor的构造去设置。但是线程池的线程数量上线是多少呢,有如何合理估算线程数量保证性能呢,如果脑子里是问号,请往下看。
总得来说,线程池的大小(上线和理想数量)由程序所处的系统和要执行的任务资源性质和程序要执行的任务类型来决定。在学习中,我们用固定的数字去测试,只能说是小demo。而在我们程序代码中往往不会去固定线程池的大小。因为根据上面提到的两个因素,我们知道线程池大小往往应该是动态的,所以应该通过动态的方式去设置线程池大小。下面我们就两面两个因素去阐述。
程序所处的系统和要执行的任务资源性质
我们可以通过java.lang.Runtime去获取jvm所在系统的cpu数量,还有jvm的可用内存,闲置内存和试图可获取的内存,分别是
Runtime runtime = Runtime.getRuntime();
int i = runtime.availableProcessors();
runtime.freeMemory()
runtime.maxMemory()
runtime.totalMemory()
当然内存的大小不是线程池大小唯一的决定因素,其他的还有比如说文件句柄,套接字句柄和数据库连接等等。它们遵循这短板效应。原则上,我们用这些资源的可用总量去除以每个任务对资源的需求量就得到了线程池大小的上线。
程序要执行的任务类型
任务类型分为计算密集型和IO密集型。先抛出一个公式
合理线程数量=CPU数量*CPU使用率*(1+等待事件/计算时间)
注意:如果是计算密集型,换句话说,线程绝大部分消耗都在CPU计算处理上,那么启动再多的线程也无济于事,所以线程数量=cpu合数比较合适。
如果是IO密集型,线程很到部分消耗在等待上,所以可以启动更多的线程,但是线程数量不能超过线程池的上限,也就是上面我们已经阐述过的计算方式。