0 0

关于ExecutorService 线程池的问题20

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;
		}
	}

}

 

2014年8月08日 09:35

2个答案 按时间排序 按投票排序

0 0

从看代码上看,线程池的数量与每批任务数量相等,处理任务结果的方式是阻塞式的,
如果某一任务没有处理结束,那么本次定时器会一直阻塞,下次定时器执行时,若又出现类似情况,则又会出现定时器阻塞,
这样每次定时器执行时,线程池都得不到释放,则线程池会增加,线程也会越来越多,时间久了,就会出现楼主说的现象

个人觉得
  在处理任务结果,可以使用带超时机制的get方法,
   同时在定时器执行时,需要判断上一次是否执行完成了,否则不能开始新的扫描过程,不然就是找“死”的结果。

2014年8月12日 20:25
0 0

任务没割30秒执行一次,每次都能在30秒之内完成么,如果没有的话,那每次任务占用的内存空间都不能释放,可能会导致内存占用比较大,可以监控下jvm堆大小、回收情况。

2014年8月08日 12:55

相关推荐

    运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接JAVA语言

    运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接

    ExecutorService线程池

    本程序实现了ExecutorService线程池,内置说明txt说明,可以参考

    运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接.doc

    运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接.doc

    在spring boot中使用java线程池ExecutorService的讲解

    今天小编就为大家分享一篇关于在spring boot中使用java线程池ExecutorService的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    使用Java并发编程实现一个简单的银行账户管理系统.txt

    在main方法中,创建了一个BankAccountManager对象和ExecutorService线程池,并初始化了1000个账户和10个线程。然后循环遍历每个账户,将每个账户提交给线程池执行转账操作。在transfer方法中,获取两个账户对象和...

    Java ExecutorService四种线程池使用详解

    主要介绍了Java ExecutorService四种线程池使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java 线程池ExecutorService详解及实例代码

    主要介绍了Java 线程池ExecutorService详解及实例代码的相关资料,线程池减少在创建和销毁线程上所花的时间以及系统资源的开销.如果不使用线程池,有可能造成系统创建大量线程而导致消耗系统内存以及”过度切换

    java线程池工具--ExecutorService,简单例子

    NULL 博文链接:https://x125858805.iteye.com/blog/2191873

    ExecutorService用法详解.doc

    接口 java.util.concurrent.ExecutorService 表述了异步执行的机制,并且...壹個 ExecutorService 实例因此特别像壹個线程池。事实上,在 java.util.concurrent 包中的 ExecutorService 的实现就是壹個线程池的实现。

    java socket线程池

     //Runtime的availableProcessors()方法返回当前系统的CPU的数目 //系统的CPU越多,线程池中工作线程的数目也越多 executorService= Executors.newFixedThreadPool(   Runtime.getRuntime()....

    最简单的爬虫-WebMagic 0.73 源码

    作为爬虫框架,它使用httpclient作为获取网页工具、使用Jsoup作为分析页面定位抓取内容、使用ExecutorService线程池作为定时增量抓取、Jdiy作为持久层框架。不熟悉这些名词的同学们可以先行百度一下这些都是什么,起...

    Executor,Executors,ExecutorService比较.docx

    Executors: 是java.util.concurrent包下的一个类,提供了若干个静态方法,用于生成不同类型的线程池。Executors一共可以创建下面这四类线程池: 1.newFixedThreadPool创建一个可缓存线程池,如果线程池长度超过...

    线程池核心组件源码剖析.docx

    该组件中,Executor 和 ExecutorService 接口 定义了线程池最核心的几个方法,提交任务 submit ()、关闭线程池 shutdown()。抽象类 AbstractExecutorService 主要对公共行为 submit()系列方法进行了实现,这些 ...

    使用Java匿名内部类实现一个简单的线程池.txt

    这段代码实现了一个简单的线程池ExecutorService,其中使用了Java的匿名内部类。在类的构造方法中,首先创建了一个固定大小为5的线程池。然后通过循环提交了10个任务到线程池中执行。每个任务都是一个匿名内部类实现...

    Java中的线程池以及Lambda表达式的应用

    一、线程池 1、什么是线程池 自定义的线程类不管是继承...public static ExecutorService newFixedThreadPool(int nThreads); 得到一个线程对象,初始化参数是要求的当前线程池中的线程数 public Future submit(Runnab

    徒手实现线程池-1

    目的是是简化并发编程 ExecutorService(执行器)Java两种基础线程池普通:ThreadPoolExecutor定时ScheduledThread

    更好的使用Java线程池

    这篇文章结合Doug Lea大神在JDK1.5提供的JCU包,分别从线程池大小参数的设置、工作线程的创建、空闲线程的回收、阻塞队列...  线程池解决的两个问题:1)线程池通过减少每次做任务的时候产生的性能消耗来优化执行大量

    线程池ThreadPoolExecutor

    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(); }

    一个小的java Demo , 非常适合Java初学者学习阅读.rar

    线程池执行者 ThreadPoolExecutor,定时执行者服务 ScheduledExecutorService, 使用 ForkJoinPool 进行分叉和合并,锁 Lock,读写锁 ReadWriteLock 原子性长整型 AtomicLong,原子性引用型 AtomicReference 修改数据:...

Global site tag (gtag.js) - Google Analytics