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线程池是Java并发编程中的核心组件,它位于`java.util.concurrent`包下,是`java.util.concurrent.Executor`接口的一个实现。ExecutorService提供了一种管理线程的方式,允许我们创建、管理和控制...
在 Spring Boot 中使用 Java 线程池 ExecutorService 的讲解 Spring Boot 作为一个流行的 Java 框架,提供了许多便捷的功能来帮助开发者快速构建应用程序。其中之一就是使用 Java 线程池 ExecutorService 来管理...
根据提供的文档标题、描述以及部分内容,我们可以总结出以下关于如何运用Java中的`concurrent.ExecutorService`线程池实现socket的TCP和UDP连接的关键知识点: ### 1. 理解Java中的`concurrent.ExecutorService` `...
线程池是多线程编程中的一个重要概念,它在Java中通过`java.util.concurrent`包中的`ExecutorService`接口及其实现类实现。线程池的使用能够有效地管理和控制线程资源,避免频繁创建和销毁线程带来的性能开销,提高...
在Java多线程编程中,`ExecutorService` 是线程池的核心接口,它提供了一种管理线程的方式,包括创建、调度和终止线程。Java的`java.util.concurrent`包中提供了`ExecutorService`的实现类,特别是通过`Executors`...
线程池可以预先创建一定数量的线程,待有任务提交时直接复用,避免了频繁创建和销毁线程的问题。此外,线程池还能通过调整线程数量来控制并发度,防止过多线程导致的资源消耗和上下文切换过度。 2. ExecutorService...
在JDK 1.5版本之前,Java对线程池的支持非常有限,而在JDK 1.5之后,加入了java.util.concurrent包,其中包含了一系列关于线程池的接口和类,极大地丰富了线程池的应用场景和管理方式。 线程池的主要作用是限制系统...
在Java中,线程池通过`java.util.concurrent`包中的`ExecutorService`接口和其相关类实现。下面将详细阐述线程池的工作原理、优势以及如何在实际应用中创建和管理线程池。 1. **线程池工作原理** 线程池由一组可...
1. Spring提供了一个名为ThreadPoolTaskExecutor的实现,它基于Java的ExecutorService接口,允许我们自定义线程池配置,如核心线程数、最大线程数、队列容量、超时时间等。 2. 通过在配置文件中声明一个...
- **关闭线程池**:在所有任务执行完毕后,调用 `executorService.shutdown()` 或 `executorService.shutdownNow()` 来优雅地关闭线程池。 6. **示例代码**: - `MyThread` 类实现了`Runnable`接口,`run`方法...
线程池通过`Executor`接口和`ExecutorService`接口提供了一套强大的机制,允许开发者高效地创建、管理和控制线程的执行。 1. **创建任务** 创建任务通常需要实现`Runnable`接口或`Callable`接口。`Runnable`接口...
Tomcat的线程池实现是基于Apache Commons JMX的ExecutorService,它是对Java标准库ExecutorService的一种扩展,增加了更多的监控和管理功能。 Tomcat的线程池主要由`org.apache.tomcat.util.threads.TaskQueue`和`...
NULL 博文链接:https://x125858805.iteye.com/blog/2191873
在Java中,`java.util.concurrent.ExecutorService`接口定义了线程池的基本行为。常用的实现类包括: 1. **FixedThreadPool**:创建一个固定大小的线程池,线程数量由用户指定。当所有线程都在执行任务时,新提交的...
这些异常反映了网络通信和线程池操作中的常见问题,如连接超时、线程池饱和和套接字关闭。捕获这些异常并记录日志有助于调试和监控系统的健康状态。 总的来说,关闭线程池是一个涉及系统稳定性、资源管理和异常处理...
Java线程池由`java.util.concurrent`包中的`ExecutorService`接口和其子类实现。其中,最常用的是`ThreadPoolExecutor`类,它提供了丰富的参数用于定制线程池的行为。线程池的核心组件包括: - **核心线程数...
Java的`java.util.concurrent`包提供了`ExecutorService`接口,它是线程池的主要入口。通过实现这个接口,我们可以控制线程的执行方式,如设置最大线程数、处理任务队列等。`ExecutorService`通常与`...
通常,我们不会直接使用`Executor`,而是使用它的子接口`ExecutorService`,因为`ExecutorService`提供了更多的功能,如任务的提交、管理和关闭线程池。 2. **Executors** `Executors`是`java.util.concurrent`包...