平时我们在项目中使用多线程时,建议不要使用jdk自带的四个创建线程池的方法:newCachedThreadPool,newFixedThreadPool,newSingleThreadExecutor,newScheduledThreadPool。这也是阿里巴巴编码规范要求的,因为这些方法使用的是无界队列,当请求比较多时,容易堆积在阻塞队列中,引发OOM。所以我们要使用下面这个构造方法来创建线程池:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
这个构造方法的参数我在另外一篇文章中(线程池—jdk提供的四种创建线程池的方法)已经详细介绍过了。这里再简单说一下:
corePoolSize:核心线程数。核心线程会一直存在,即使没有任务执行;当线程数小于核心线程数的时候,即使有空闲线程,也会一直创建线程直到达到核心线程数;通常设置为1就可以了。
maxPoolSize:最大线程数。是线程池里允许存在的最大线程数量;
keepAliveTime:线程空闲时间。当线程空闲时间达到keepAliveTime时,线程会退出(关闭),直到线程数等于核心线程数。
workQueue:阻塞队列。建议使用有界队列,比如ArrayBlockingQueue
ThreadFactory:线程创建工厂。一般用来设置线程名称的。
handler:拒绝策略。一般用来做日志记录等。
重点来啦:
我们说设置线程池大小,主要是设置最大线程的数量,即maxPoolSize参数的大小。那这个应该设置成多少合适呢?首先我们要分两种情况,即CPU密集型和IO密集型任务。
CPU密集型任务:即需要大量计算的任务,因为计算是由CPU来完成的,所以称之为CPU密集型任务。这个时候设置为CPU核心数+1就可以了。
IO密集型任务:即需要通过网络来交互的任务,通常是指数据库数据交互、文件上传下载、网络数据传输等任务。这个时候需要设置为CPU核心数*2。但是实际情况中可以通过自己的测试来设置合理的数值,通过与大牛的交流得知,这个数值可以设置为CPU核心数/(1-阻塞系数),阻塞系数一般在0.8~0.9之间。比如8核CPU可以设置为:8*(1-0.9)=80。
注意:在java中获取CPU核心数可以用以下代码:
Runtime.getRuntime().availableProcessors();
