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


    一、 问题描述 
    先来看一下异常信息,启动tomcat时就报错: 

    Java代码  收藏代码
    1. 2015-3-20 15:22:39 org.apache.catalina.core.StandardContext listenerStart  
    2. 严重: Exception sending context initialized event to listener instance of class  
    3. com.***.***.action.GateWayMonitorListener  
    4. java.util.concurrent.RejectedExecutionException  
    5.         at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution  
    6. (ThreadPoolExecutor.java:1774)  
    7.         at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.jav  
    8. a:768)  
    9.         at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(Sched  
    10. uledThreadPoolExecutor.java:215)  
    11.         at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDel  
    12. ay(ScheduledThreadPoolExecutor.java:443)  
    13.         at com.***.***.action.GateWayMonitorListener  
    14. .scheduleEmailAndSms(GateWayMonitorListener.java:77)  
    15.         at com.***.***.action.GateWayMonitorListener  
    16. .contextInitialized(GateWayMonitorListener.java:67)  
    17.         at org.apache.catalina.core.StandardContext.listenerStart(StandardContex  
    18. t.java:4206)  
    19.         at org.apache.catalina.core.StandardContext.start(StandardContext.java:4  
    20. 705)  
    21.         at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase  
    22. .java:799)  
    23.         at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:77  
    24. 9)  
    25.         at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:601)  
    26.   
    27.         at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.jav  
    28. a:1079)  
    29.         at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.j  
    30. ava:1002)  
    31.         at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:506  
    32. )  
    33.         at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1317)  
    34.         at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java  
    35. :324)  
    36.         at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(Lifecycl  
    37. eSupport.java:142)  
    38.         at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1065)  
    39.   
    40.         at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)  
    41.         at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)  
    42.   
    43.         at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463  
    44. )  
    45.         at org.apache.catalina.core.StandardService.start(StandardService.java:5  
    46. 25)  
    47.         at org.apache.catalina.core.StandardServer.start(StandardServer.java:754  
    48. )  
    49.         at org.apache.catalina.startup.Catalina.start(Catalina.java:595)  
    50.         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    51.         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.  
    52. java:39)  
    53.         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces  
    54. sorImpl.java:25)  
    55.         at java.lang.reflect.Method.invoke(Method.java:597)  
    56.         at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)  
    57.         at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)  
    58. 2015-3-20 15:22:39 org.apache.catalina.core.StandardContext start  
    59. 严重: Error listenerStart  



    再来看看相关源码: 

    Java代码  收藏代码
    1. public class GateWayMonitorListener implements ServletContextListener, ApplicationContextAware  
    2. {  
    3.     /** 
    4.      *  设定两个线程,一个用来定期发送巡检短信;另一个定期执行三大运营商网关监控。 
    5.      */  
    6.     public static ScheduledExecutorService service = Executors.newScheduledThreadPool(2);  
    7.   
    8.     public void contextInitialized(ServletContextEvent event)  
    9.     {         
    10.         // 网关监测  
    11.         GateWayMonitorListener.service.scheduleWithFixedDelay(new MonitorTask(), 60, MonitorConfigCache.lastPollingIntervalSecond, TimeUnit.SECONDS);  
    12.         // 定时每天固定时间发送短信  
    13.         GateWayMonitorListener.service.scheduleAtFixedRate(new EveryDaySmsTask(), calculateIntialDelay(), GateWayMonitorListener.ONE_DAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS);  
    14.     }  
    15. }  
    16.   
    17. /** 
    18.      * 按新时间间隔重新设置定时任务。 
    19.      *  
    20.      * @param interval 
    21.      */  
    22.     public static synchronized void resetMonitorTaskInterval()  
    23.     {  
    24.         // 关闭老的线程池  
    25.         GateWayMonitorListener.service.shutdownNow();  
    26.                   
    27.         try  
    28.         {  
    29.             GateWayMonitorListener.service.awaitTermination(60, TimeUnit.SECONDS);  
    30.         }  
    31.         catch (InterruptedException e)  
    32.         {  
    33.             log.warn("InterruptedException when shutdown old threadPool", e);  
    34.         }  
    35.         catch (Exception e)  
    36.         {  
    37.             log.error("other exception when shutdown old threadPool", e);  
    38.         }  
    39.           
    40.         GateWayMonitorListener.service = Executors.newScheduledThreadPool(2);  
    41.           
    42.         // 重新设置定时任务。  
    43.         …  
    44.     }  



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

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

    三、 问题解决 
    控制线程池的shutdown调用,调用后不能再往线程池里加入线程。 

    原文地址:http://zoroeye.iteye.com/blog/2194390

  • 相关阅读:
    js正则表达式基本语法
    类似于QQ的右滑删除效果的实现方法
    JS设置cookie、读取cookie、删除cookie
    JavaScript随机生成颜色的方法
    mysql数据库备份及恢复
    Javascript 实现简单计算器实例代码
    JavaScript 实现的checkbox经典实例分享
    网页瀑布流布局jQuery实现代码
    Django Web在Apache上的部署
    VIM使用系列之一——配置VIM下C/C++编程环境
  • 原文地址:https://www.cnblogs.com/heart-king/p/5235277.html
Copyright © 2020-2023  润新知