当前位置:   article > 正文

<线程池-定时任务> ScheduledExecutorService之shutdown引发的RejectedExecutionException问题...

<线程池-定时任务> ScheduledExecutorService之shutdown引发的RejectedExecutionException问题...
[b]一、 问题描述[/b]
[b]先来看一下异常信息,启动tomcat时就报错:[/b]
2015-3-20 15:22:39 org.apache.catalina.core.StandardContext listenerStart严重: Exception sending context initialized event to listener instance of classcom.***.***.action.GateWayMonitorListenerjava.util.concurrent.RejectedExecutionException        at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1774)        at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:768)        at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:215)        at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:443)        at com.***.***.action.GateWayMonitorListener.scheduleEmailAndSms(GateWayMonitorListener.java:77)        at com.***.***.action.GateWayMonitorListener.contextInitialized(GateWayMonitorListener.java:67)        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:799)        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:779)        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)        at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1079)        at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:1002)        at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:506)        at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317)        at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:324)        at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065)        at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)        at org.apache.catalina.core.StandardService.start(StandardService.java:525)        at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)        at org.apache.catalina.startup.Catalina.start(Catalina.java:595)        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)        at java.lang.reflect.Method.invoke(Method.java:597)        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)2015-3-20 15:22:39 org.apache.catalina.core.StandardContext start严重: Error listenerStart


[b]再来看看相关源码:[/b]
public class GateWayMonitorListener implements ServletContextListener, ApplicationContextAware{	/**	 *  设定两个线程,一个用来定期发送巡检短信;另一个定期执行三大运营商网关监控。	 */	public static ScheduledExecutorService service = Executors.newScheduledThreadPool(2);    public void contextInitialized(ServletContextEvent event)	{				// 网关监测	    GateWayMonitorListener.service.scheduleWithFixedDelay(new MonitorTask(), 60, MonitorConfigCache.lastPollingIntervalSecond, TimeUnit.SECONDS);		// 定时每天固定时间发送短信		GateWayMonitorListener.service.scheduleAtFixedRate(new EveryDaySmsTask(), calculateIntialDelay(), GateWayMonitorListener.ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS);	}}/**	 * 按新时间间隔重新设置定时任务。	 * 	 * @param interval	 */	public static synchronized void resetMonitorTaskInterval()	{		// 关闭老的线程池		GateWayMonitorListener.service.shutdownNow();		try		{			GateWayMonitorListener.service.awaitTermination(60, TimeUnit.SECONDS);		}		catch (InterruptedException e)		{			log.warn("InterruptedException when shutdown old threadPool", e);		}		catch (Exception e)		{			log.error("other exception when shutdown old threadPool", e);		}		GateWayMonitorListener.service = Executors.newScheduledThreadPool(2);		// 重新设置定时任务。		…	}


没有列出的还有另一个类会定时重新加载定时任务的配置文件,如果配置文件修改了定时任务执行的时间设置,则重新配置定时任务,起到热加载配置文件的目的。也就是会调用resetMonitorTaskInterval()方法。

[b]二、 问题分析[/b]
Tomcat一启动就报错[color=red]RejectedExecutionException[/color],
(1)根据jdk描述何时回抛出这个异常:if the task cannot be scheduled for execution,只是说任务在不能被加入线程池时会抛出这个异常,不够明确。
(2)进一步分析什么时候线程池不能加入线程来执行,如果不是线程池还未被初始化好,线程池已满且策略是超过的会被拒绝外,就是线程池被shutdown了。Tomcat一启动就报错,而且线程池是在最上面static的,那应该就是被shutdown了。查看是否有哪里调用shutdown方法了。
(3)再分析,果然在另一个线程处会调用重新设置线程池的方法resetMonitorTaskInterval(),而且里面调用了shutdown。问题找到了,第一次读配置文件时就触发了重新设置定时任务。这是不行滴。。第一次只算是初始化,后面发现变更才应该重设线程池。但一定要控制同步,保证shutdown之后没有再往旧线程池中加入定时任务。

[b]三、 问题解决[/b]
控制线程池的shutdown调用,调用后不能再往线程池里加入线程。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/83681
推荐阅读
相关标签
  

闽ICP备14008679号