线程池的最佳实践


一、线程池的最佳实践

1、正确创建线程池

线程池应该避免使用Executors类来创建,而应该用ThreadPoolExecutor类来创建,避免出现OOM。(具体可参考《线程池有哪几种?为什么不建议用Executors创建?》

2、监控线程池运行状态

为了能直观观察线程池运行状态,我们可以定时对线程池的一些参数进行监控,具体代码如下:

public static void printThreadPoolStatus(ThreadPoolExecutor threadPoolExecutor) {
    log.info("===========");
    log.info("ThreadPool Size:" + threadPoolExecutor.getPoolSize());
    log.info("Active Threads:" + threadPoolExecutor.getActiveCount());
    log.info("Total Tasks:" + threadPoolExecutor.getCompletedTaskCount());
    log.info("Total Tasks in Queue:" + threadPoolExecutor.getQueue().getSize());
    log.info("===========");
}

3、不同的业务场景区分使用不同的线程池

首先不同的业务场景可能的资源使用情况不一样,所以对于线程池的参数配置也是不一样的,另外还容易出现死锁的情况。(具体可参考《没做线程池隔离导致的线上故障分析》

4、线程池命名

为了方便定位问题,我们一般会将线程池命名,比如orderThreadPool-1userLoginThreadPool-5

5、正确配置线程池参数

  • 核心线程数:如果是IO密集型任务,则设置为2N,如果是CPU密集型任务,则设置为N+1
  • 最大线程数:一般和核心线程数相等,避免出现频繁的线程创建销毁
  • 拒绝策略:根据业务场景选择合适的拒绝策略,一般默认选择AbortPolicy即可

二、Q&A

1、线程池的阻塞队列要设置多大合适?

正常情况下,我们的阻塞大小都是设置几百即可,太大的话消费缓慢,太小的话会拒绝太多请求。

但如果从科学的角度来看,阻塞队列的大小决定了满之后请求的效率。

打个比方,我们有一个接口,它的平均耗时是50ms,系统超时时间是3000ms

  • 那么最大线程数为1的情况下,理论上每秒可以处理20个请求
  • 假设阻塞队列最后一个元素执行完刚好超时,也就是3000ms,那么阻塞队列的大小就是3000ms/50ms=60(也就是说,最大线程为1,阻塞队列为60,最差情况请求耗时为3000ms)

那如果我们最大线程数调整为5,那么相对应的阻塞队列大小就可以调整为3000ms/50ms*5=300(也就是说,最大线程为5,阻塞队列为300,最差情况请求耗时为15000ms)

但如果我们调整阻塞队列为100,就会出现队列满之后的请求延时较高,具体计算为50ms5100=15000ms(也就是说,最大线程为5,阻塞队列为100,最差情况请求耗时为15000ms)

结论:所以说,阻塞队列大小的设置一般要参考最大线程数、请求平均时延、请求超时时延等因素综合考虑得到一个合理的值,不应该过大,也不应该过小。

2、线程池的线程数为什么要根据CPU核心数去设置?

我们知道,线程池线程数的最佳实践是根据CPU核心数来计算:

  • CPU密集型:CPU核心数+1
  • IO密集型:2*CPU核心数

为什么CPU密集型的线程数是CPU核心数+1?

CPU密集型指的是使用CPU计算,比如我使用线程打印1到100,那是不是线程越多越好呢?答案不是,因为我们要考虑到CPU核心数,如果只有1个CPU核心,那么越多的线程只会带来越多的线程切换导致的性能消耗。(相比之下,用1个线程去打印1到100效率更高)

所以按理说,CPU核心数有多少,那么线程数设置多少就行,那么多出来的1个线程是有什么用呢?是为了防止某个线程阻塞导致CPU没有跑满,所以额外加了1个线程。

为什么IO密集型的线程数是2*CPU核心数?

IO密集型指的是IO操作比较多的任务,比如网络IO、磁盘IO等,这些都不涉及CPU使用,但是由于IO需要耗时,所以线程数要比CPU密集型的线程数多。防止线程都阻塞在IO上,导致CPU没活干了,所以线程数我们给设置为2CPU核心数。(当然,具体参数还需要看具体场景来调整,比如通过压测来确定最佳线程数,避免说2CPU核心数的线程也都阻塞在IO上了)


文章作者: GaryLee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 GaryLee !
  目录