JAVA线程池资源回收的问题
最近项目中为了提高用户体验度,前台创建任务后台任务,用多线程来跑。
现在的场景:后台定时任务管理这两个线程池,一个最大线程数10个,一个最大线程数15。应用部署之后,不超过5个小时,服务器负载高,内存使用过多。
分析原因:因为这个功能是excel导入功能,如果前台有大量的导入任务时,那么后台的负载就会很高。
我的实现原理:定时任务读取任务,放到任务队列表中,然后使用线程池消费任务队列中的任务,每个线程时一直循环取任务。
我的定时任务周期是 1 分钟,线程池从初始化时,空闲线程存活的时间为 1 分钟,任务队列没有设定最大数量值。
优化:
1.任务队列没有上限
定时任务每次启动都回去数据库中读取任务,放入对列表中,如果一直往任务队列中放,那么任务队列占用的内存会越来越大,导致服务器内存不足。
解决办法:定时任务在读取任务时,先判断任务队列的大小,比如我这设置的100个,那么我就不再读取新的任务了。这个参数需要通过观察机器的负载,然后来调整。
2.线程池中的线程,无限循环处理任务,当任务数量过多的时候,线程会一直执行,停不下来。
线程池中的线程,无限循环处理任务,当任务数量过多的时候,线程会一直执行,停不下来。
解决办法:在线程内部设置计数器,当一个线程累计到一定数量,退出循环,然后清空资源,回收,间歇性,周期的执行任务,相当于定期回收资源
3.定时任务 1 分钟,那么空闲线程存活的时间为1分钟
由于空闲线程存活时间是 1 分钟,那么我的定时任务也是 1 分钟,这个时候,线程就基本就不会被线程池回收,那么资源就一直没有释放,被回收。
解决办法:调整线程空闲的线程存活时间为定时任务周期的一半,也就是30秒。
4.在线程池中,有核心线程,对于核心线程超时也回收,所以,需要执行下边这个方法,确保核心线程超时之后也被回收。
解决办法:threadPoolExecutor.allowCoreThreadTimeOut(true);
优化之后的流程:
任务定期读取任务,往任务队列中放一定量(不能超过最大值)的任务,之后线程池中的线程超时时间设置短一点,线程通过计数器,当执行了一定数量的线程之后,推出循环,这个时候线程就空闲了,后边就会被线程池回收,资源被回收,如此反复进行下去,资源回收,重新分配,不会大量消耗服务资源。
通过以上几个点的优化,程序消耗服务器资源好很多,可能还有优化的地方,后边再补充。