我们对线程池负责执行的任务分为三种情况:
(1)CPU密集型任务,比如找出1-1000000中的素数。
CPU密集型任务的特点,线程在执行任务时会一直使用CPU,所以对于这种情况,就要尽量避免发生线程上下文的切换。比如我们至于一个CPU,如果这两个吸纳成同时执行找素数的任务,那么这个CPU就需要进行额外的上下文切换,从而达到线程并行的效果。
所以对于CPU密集型的任务,线程数量最好就等于核心线程数。
只不过,为了应对线程执行过程发生缺页中断或者其他异常导致线程阻塞的请求,我们可以额外多设置一个线程,这样当某个线程不需要CPU时,可以有替补线程继续使用CPU。
所以对于CPU密集型任务,我们可以设置线程数为CPU核心数+1。
(2)IO密集型任务,比如文件IO、网络IO
线程在执行IO型任务时,可能大量时间都阻塞在IO上,假如现在有10个CPU,如果我们只设置了10个线程来执行IO型任务,那么可能这10个线程都阻塞在了IO上,这样10个CPU都没活干了,所以我们通常设置为2*CPU核心数。
通常,如果IO型任务执行的时间越长,那么阻塞在IO上的线程就越多,我们可以设置更多的线程,但是线程并不是越多越好,我们可以通过下式计算:
线程数 = CPU核心数 * (1 + 线程等待时间 / 线程运行总时间)
线程等待时间:线程没有使用CPU的时间
线程总时间:指的是线程执行完某个任务的总时间
可以使用jvisualvm抽样来估计这两个时间。
(3)混合型任务