2012-03-29 176 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()退出。