平时我们在项目中使用多线程时,建议不要使用jdk自带的四个创建线程池的方法:newFixedThreadPool,newSingleThreadExecutor,newCachedThreadPool,newScheduledThreadPool。这也是阿里巴巴编码规范要求的。
FixedThreadPool和SingleThreadPoolPool : 使用的是无界队列,允许的请求队列长度为 Integer.MAX_VALUE,可能导致堆积大量请求在队列中;
newCachedThreadPool,newScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,相当于可以无限制创建线程,可能导致创建大量线程。
这四个创建线程池的方法都容易导致OOM问题,有潜在的宕机风险。
所以在可能有大量请求的线程池场景中, 更推荐自定义ThreadPoolExecutor来创建线程池, 具体构造函数配置见下文.
ublic ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:核心线程数。核心线程会一直存在,即使没有任务执行;当线程数小于核心线程数的时候,即使有空闲线程,也会一直创建线程直到达到核心线程数;通常设置为1就可以了。
maximumPoolSize:最大线程数。是线程池里允许存在的最大线程数量;
keepAliveTime:线程空闲时间。当线程空闲时间达到keepAliveTime时,线程会退出(关闭),直到线程数等于核心线程数。
workQueue:阻塞队列。建议使用有界队列,比如ArrayBlockingQueue先进先出队列,创建时指定大小
ThreadFactory:线程创建工厂。一般用来设置线程名称的。
handler:拒绝策略。一般用来做日志记录等。
线程池大小配置
一般根据任务类型进行区分, 假设CPU为N核
- CPU密集型任务,即需要进行大量计算的任务,需要减少线程数量, 降低线程切换造成的开销, 可配置线程池大小为N + 1.
- IO密集型任务,即需要通过网络来交互的任务,通常是指数据库数据交互、文件上传下载、网络数据传输等任务。可以加大线程数量, 配置线程池大小为 N * 2。但实际情况中可以通过自己的测试来设置合理的数值,通过与大牛的交流得知,这个数值可以设置为CPU核心数/(1-阻塞系数),阻塞系数一般在0.8~0.9之间。比如8核CPU可以设置为:8*(1-0.9)=80。
- 混合型任务则可以拆分为CPU密集型与IO密集型, 独立配置.
- 注意:在java中获取CPU核心数可以用以下代码:Runtime.getRuntime().availableProcessors();
线程池的使用可参考文章:
https://www.cnblogs.com/nankeyimengningchenlun/p/9132987.html
https://www.cnblogs.com/wood-lin/p/4221331.html
https://www.jianshu.com/p/f6024f806534