2012-03-29 178 views
3

我想在关闭Tomcat时关闭线程。
具体而言,我试图关闭log4j看门狗(for filechanges),我也试图关闭在我的web应用程序中使用类的执行程序。
关闭时,我在Catalina.out中看到异常。
对于Log4J的我看到:当tomcat关闭时关闭线程的正确方法是什么?

INFO: Illegal access: this web application instance has been stopped
already. Could not load org.apache.log4j.helpers.NullEnumeration.
The eventual following stack trace is caused by an error thrown for
debugging purposes as well as to attempt to terminate the thread which
caused the illegal access, and has no functional impact. Throwable
occurred: java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at org.apache.log4j.Category.getAllAppenders(Category.java:413)
at org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
at org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
at org.apache.log4j.LogManager.shutdown(LogManager.java:267)
at com.listeners.myListener$1.run(myListener.java:232)
Exception in thread "Thread-14" java.lang.NoClassDefFoundError:
org.apache.log4j.helpers.NullEnumeration
at org.apache.log4j.Category.getAllAppenders(Category.java:413)
at org.apache.log4j.Category.closeNestedAppenders(Category.java:226)
at org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467)
at org.apache.log4j.LogManager.shutdown(LogManager.java:267)

而对于执行的部分:

INFO: Illegal access: this web application instance has been stopped
already. Could not load com.my.class.SomeClass. The eventual
following stack trace is caused by an error thrown for debugging
purposes as well as to attempt to terminate the thread which caused
the illegal access, and has no functional impact. Throwable occurred:
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
at Exception in thread "Thread-13" java.lang.NoClassDefFoundError:
com.my.class.SomeClass

什么我做的是在ServletContextListenercontextDestroyed我已经加入关闭挂钩如下:

public void contextDestroyed(ServletContextEvent arg0) { 

     Runtime.getRuntime().addShutdownHook(new Thread(){ 
      @Override 
      public void run(){ 
       LogManager.shutdown();     
      } 
     }); 

    } 





public void contextDestroyed(ServletContextEvent arg0) { 

     Runtime.getRuntime().addShutdownHook(new Thread(){ 
      @Override 
      public void run(){ 
       SomeClass.updater.shutdown(); 
      } 
     }); 

    } 

我在这里做错了什么?为什么我会遇到异常?

UPDATE:
SomeClass.updaterpublic static ScheduledExecutorService
LogManagerorg.apache.log4j.LogManager

UPDATE2:
后从BGR回答以下我直接做

public void contextDestroyed(ServletContextEvent arg0) { 

      SomeClass.updater.shutdown(); 

     } 

public void contextDestroyed(ServletContextEvent arg0) { 

       LogManager.shutdown();     

     } 

我没有得到Log4j的例外,但我得到SomeClass.updater这是一个public static ScheduledExecutorService的以下例外:

INFO: Illegal access: this web application instance has been stopped
already. Could not load java.util.concurrent.ExecutorService. The
eventual following stack trace is caused by an error thrown for
debugging purposes as well as to attempt to terminate the thread which
caused the illegal access, and has no functional impact. Throwable
occurred: java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)

为什么?这些课程已经被垃圾收集了吗?

回答

2

我会在servlet的init()方法而不是contextDetroyed()中注册关闭钩子,但无论如何,您为什么需要首先关闭钩子?

难道你不能直接在contextDestroyed()方法中调用SomeClass.updater.shutdown();

编辑

听者的contextDestroyed()是迟到的执行服务。由JavaDoc规定所有的servlet和过滤器将已经任何的ServletContextListener通知情况下破坏之前破坏

而重写的servlet destroy()应作为根据的Javadoc 这种方法确定给servlet的一个机会,清理正在举行的任何资源(例如,内存,文件句柄,线程 .. 。

@Override 
public void destroy() { 


     myThreadExecutor.shutdown(); 

     super.destroy(); 
} 
+0

我认为使用关闭挂钩,以便我确信他们在JVM关闭时被调用 – Jim 2012-03-29 08:56:48

+0

相信您的容器:-)。无论如何,请尽早注册。我会去找servlet的init()方法。 – 2012-03-29 09:09:47

+0

你能看到更新吗? – Jim 2012-03-29 09:19:03

2

调用

LogManager.shutdown(); 
在contextDestroyed()方法

是第一步,但ExecutorService的不立即关闭。您正在获取异常,因为ExecutorService线程在contextDestroyed()方法返回后仍在运行。你需要做的:

public void contextDestroyed(ServletContextEvent arg0) { 
    LogManager.shutdown(); 
    if(LogManager.awaitTermination(10, TimeUnit.SECONDS) == false) { 
     LogManager.shutdownNow(); 
    } 
} 

这样的线程池已关闭,停止所有线程时contextDestroyed()退出。