1.背景:
想要实现一个多线程扫描的功能,使用spring @Scheduled 设定扫描计划,每隔30s创建线程执行扫描任务.
2.出现的问题:
Scheduled 计划执行几天的时间后就会不再执行(方法里有日志输出,但不再打印),出现此问题后,系统还是可以正常访问,log中没有扫描日志
网上查询 了一下,有人说是内存过低有可能导致Scheduled停止.
3.请问下面的代码有没有什么问题会导致内存泄露,关键代码已用红色标注
//相关引用 @Component public class ScheduledScanTimer { private final Logger log = Logger.getLogger(getClass()); private SimpleDateFormat sf = new SimpleDateFormat("HH:mm"); private FiberScanTaskService scanTaskService; private FiberService fiberService; private FiberLogInfoService fiberLogInfoService; private FiberSDFIService fiberSDFIService; @Scheduled(fixedDelay = 30000) public void fiberScan() { log.info("@Scheduled start......................"); List<Future<List<ScanResult>>> scanList = new ArrayList<Future<List<ScanResult>>>();// 扫描结果 // 整理扫描结果 StringBuffer scanResultStr = new StringBuffer(); StringBuffer fiberScanIDs = new StringBuffer(); try { // 获取检查任务sql语句 String sql = getScanSql(); List<FiberScanTask> taskList = scanTaskService.getFiberScanTaskByScanTime(sql); // 检查是否有执行任务 if (taskList != null && taskList.size() > 0) { log.info("have task to execute!"); for (FiberScanTask task : taskList) { // 设置任务状态为扫描中... task.setTaskStatus(1); scanTaskService.editFiberScanTask(task, false); // 获取光纤Ids String fiberIds = task.getFiberIds(); // 对要扫描的光纤Ids按照sfdi分组 List<ScanThread> scanThreadList = fiberService.getThreadGroupByFiberIds(fiberIds); // 初始化指定个数的线程池 ExecutorService pool = Executors.newFixedThreadPool(taskList.size()); for (ScanThread st : scanThreadList) { Callable<List<ScanResult>> callable = new FiberScanner(st.getFiberIds(), fiberService, fiberLogInfoService, fiberSDFIService); Future<List<ScanResult>> future = pool.submit(callable); scanList.add(future); } // 遍历线程返回结果 for (Future<List<ScanResult>> fu : scanList) { List<ScanResult> resList = fu.get(); for (ScanResult scanResult : resList) { scanResultStr.append(scanResult.getScanResultStr() + "<br>"); fiberScanIDs.append(scanResult.getScanRecordId() + ","); } } // 关闭线程池 pool.shutdown(); } } else { log.info("no execute task !"); // 更新无效任务状态 updateInvalidTask(); } } catch (InterruptedException e) { log.error("FiberController.java fiberScan()," + e.getMessage()); e.printStackTrace(); } catch (ExecutionException e) { log.error("FiberController.java fiberScan()," + e.getMessage()); e.printStackTrace(); } finally { scanList.clear(); scanList = null; scanResultStr = fiberScanIDs = null; } } }
如果换成 newCachedThreadPool 修改成下面的会不会好些?
//相关引用 @Component public class ScheduledScanTimer { private final Logger log = Logger.getLogger(getClass()); private SimpleDateFormat sf = new SimpleDateFormat("HH:mm"); private FiberScanTaskService scanTaskService; private FiberService fiberService; private FiberLogInfoService fiberLogInfoService; private FiberSDFIService fiberSDFIService; private ExecutorService pool ; @Scheduled(fixedDelay = 30000) public void fiberScan() { log.info("@Scheduled start......................"); List<Future<List<ScanResult>>> scanList = new ArrayList<Future<List<ScanResult>>>();// 扫描结果 // 整理扫描结果 StringBuffer scanResultStr = new StringBuffer(); StringBuffer fiberScanIDs = new StringBuffer(); try { // 获取检查任务sql语句 String sql = getScanSql(); List<FiberScanTask> taskList = scanTaskService.getFiberScanTaskByScanTime(sql); // 检查是否有执行任务 if (taskList != null && taskList.size() > 0) { log.info("have task to execute!"); // 初始化指定个数的线程池 pool = Executors.newCachedThreadPool(); for (FiberScanTask task : taskList) { // 设置任务状态为扫描中... task.setTaskStatus(1); scanTaskService.editFiberScanTask(task, false); // 获取光纤Ids String fiberIds = task.getFiberIds(); // 对要扫描的光纤Ids按照sfdi分组 List<ScanThread> scanThreadList = fiberService.getThreadGroupByFiberIds(fiberIds); for (ScanThread st : scanThreadList) { Callable<List<ScanResult>> callable =new FiberScanner(st.getFiberIds(),fiberService,fiberLogInfoService,fiberSDFIService); Future<List<ScanResult>> future = pool.submit(callable); scanList.add(future); } // 遍历线程返回结果 for (Future<List<ScanResult>> fu : scanList) { List<ScanResult> resList = fu.get(); for (ScanResult scanResult : resList) { scanResultStr.append(scanResult.getScanResultStr() + "<br>"); fiberScanIDs.append(scanResult.getScanRecordId() + ","); } } } } else { log.info("no execute task !"); // 更新无效任务状态 updateInvalidTask(); } } catch (InterruptedException e) { // 关闭线程池 pool.shutdown(); log.error("FiberController.java fiberScan()," + e.getMessage()); e.printStackTrace(); } catch (ExecutionException e) { // 关闭线程池 pool.shutdown(); log.error("FiberController.java fiberScan()," + e.getMessage()); e.printStackTrace(); } finally { scanList.clear(); scanList = null; scanResultStr = fiberScanIDs = null; } } }
相关推荐
运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接
本程序实现了ExecutorService线程池,内置说明txt说明,可以参考
运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接.doc
今天小编就为大家分享一篇关于在spring boot中使用java线程池ExecutorService的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
在main方法中,创建了一个BankAccountManager对象和ExecutorService线程池,并初始化了1000个账户和10个线程。然后循环遍历每个账户,将每个账户提交给线程池执行转账操作。在transfer方法中,获取两个账户对象和...
主要介绍了Java ExecutorService四种线程池使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了Java 线程池ExecutorService详解及实例代码的相关资料,线程池减少在创建和销毁线程上所花的时间以及系统资源的开销.如果不使用线程池,有可能造成系统创建大量线程而导致消耗系统内存以及”过度切换
NULL 博文链接:https://x125858805.iteye.com/blog/2191873
接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且...壹個 ExecutorService 实例因此特别像壹個线程池。事实上,在 java.util.concurrent 包中的 ExecutorService 的实现就是壹個线程池的实现。
//Runtime的availableProcessors()方法返回当前系统的CPU的数目 //系统的CPU越多,线程池中工作线程的数目也越多 executorService= Executors.newFixedThreadPool( Runtime.getRuntime()....
作为爬虫框架,它使用httpclient作为获取网页工具、使用Jsoup作为分析页面定位抓取内容、使用ExecutorService线程池作为定时增量抓取、Jdiy作为持久层框架。不熟悉这些名词的同学们可以先行百度一下这些都是什么,起...
Executors: 是java.util.concurrent包下的一个类,提供了若干个静态方法,用于生成不同类型的线程池。Executors一共可以创建下面这四类线程池: 1.newFixedThreadPool创建一个可缓存线程池,如果线程池长度超过...
该组件中,Executor 和 ExecutorService 接口 定义了线程池最核心的几个方法,提交任务 submit ()、关闭线程池 shutdown()。抽象类 AbstractExecutorService 主要对公共行为 submit()系列方法进行了实现,这些 ...
这段代码实现了一个简单的线程池ExecutorService,其中使用了Java的匿名内部类。在类的构造方法中,首先创建了一个固定大小为5的线程池。然后通过循环提交了10个任务到线程池中执行。每个任务都是一个匿名内部类实现...
一、线程池 1、什么是线程池 自定义的线程类不管是继承...public static ExecutorService newFixedThreadPool(int nThreads); 得到一个线程对象,初始化参数是要求的当前线程池中的线程数 public Future submit(Runnab
目的是是简化并发编程 ExecutorService(执行器)Java两种基础线程池普通:ThreadPoolExecutor定时ScheduledThread
这篇文章结合Doug Lea大神在JDK1.5提供的JCU包,分别从线程池大小参数的设置、工作线程的创建、空闲线程的回收、阻塞队列... 线程池解决的两个问题:1)线程池通过减少每次做任务的时候产生的性能消耗来优化执行大量
ExecutorService:真正的线程池接口 void execute(Runnable command) :执行任务/命令,没有返回值,一般用来执行Runnable Future submit(Callable task):执行任务,有返回值,一般又来执行Callable void shutdown...
按先后顺序执行线程 ... ExecutorService t = Executors.newSingleThreadExecutor(); for (int i = 0; i ; i++) { t.submit(new AA(i)); } System.out.println("kkkkkkkkkk"); t.shutdown(); }
线程池执行者 ThreadPoolExecutor,定时执行者服务 ScheduledExecutorService, 使用 ForkJoinPool 进行分叉和合并,锁 Lock,读写锁 ReadWriteLock 原子性长整型 AtomicLong,原子性引用型 AtomicReference 修改数据:...