我正在尝试在关闭Tomcat时关闭线程。具体来说,我正在尝试关闭log4j watchdog(用于文件更改),并且我还尝试关闭使用我的Web应用程序中的类的执行器。关闭时,我在Catalina.out中看到异常。对于Log4J,我看到:
INFO:非法访问:此Web应用程序实例已停止。无法加载org.apache.log4j.helpers.NullEnumeration。以下最终堆栈跟踪是由于为了调试目的而抛出错误以及尝试终止导致非法访问的线程,并且没有功能影响。Throwable发生了: java.lang.IllegalStateException 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587) 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546) 在org.apache.log4j.Category.getAllAppenders(Category.java:413) 在org.apache.log4j.Category.closeNestedAppenders(Category.java:226) 在org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467) 在org.apache.log4j.LogManager.shutdown(LogManager.java:267) 在com.listeners.myListener $ 1.run(myListener.java:232) 线程“Thread-14”中的异常java.lang.NoClassDefFoundError: org.apache.log4j.helpers.NullEnumeration 在org.apache.log4j.Category.getAllAppenders(Category.java:413) 在org.apache.log4j.Category.closeNestedAppenders(Category.java:226) 在org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467) 在org.apache.log4j.LogManager.shutdown(LogManager.java:267)
对于执行器部分:
INFO:非法访问:此Web应用程序实例已停止。无法加载com.my.class.SomeClass。以下最终堆栈跟踪是由于为了调试目的而抛出错误以及尝试终止导致非法访问的线程,并且没有功能影响。Throwable发生了: java.lang.IllegalStateException 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587) 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546) 在 线程“Thread-13”中的异常java.lang.NoClassDefFoundError: com.my.class.SomeClass
我在ServletContextListener上的contextDestroyed中添加了关闭挂钩,如下所示:
我没有从Log4j中得到异常,但是我收到了以下关于
INFO:非法访问:此Web应用程序实例已停止。无法加载org.apache.log4j.helpers.NullEnumeration。以下最终堆栈跟踪是由于为了调试目的而抛出错误以及尝试终止导致非法访问的线程,并且没有功能影响。Throwable发生了: java.lang.IllegalStateException 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587) 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546) 在org.apache.log4j.Category.getAllAppenders(Category.java:413) 在org.apache.log4j.Category.closeNestedAppenders(Category.java:226) 在org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467) 在org.apache.log4j.LogManager.shutdown(LogManager.java:267) 在com.listeners.myListener $ 1.run(myListener.java:232) 线程“Thread-14”中的异常java.lang.NoClassDefFoundError: org.apache.log4j.helpers.NullEnumeration 在org.apache.log4j.Category.getAllAppenders(Category.java:413) 在org.apache.log4j.Category.closeNestedAppenders(Category.java:226) 在org.apache.log4j.Hierarchy.shutdown(Hierarchy.java:467) 在org.apache.log4j.LogManager.shutdown(LogManager.java:267)
对于执行器部分:
INFO:非法访问:此Web应用程序实例已停止。无法加载com.my.class.SomeClass。以下最终堆栈跟踪是由于为了调试目的而抛出错误以及尝试终止导致非法访问的线程,并且没有功能影响。Throwable发生了: java.lang.IllegalStateException 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587) 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546) 在 线程“Thread-13”中的异常java.lang.NoClassDefFoundError: com.my.class.SomeClass
我在ServletContextListener上的contextDestroyed中添加了关闭挂钩,如下所示:
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();
}
});
}
我在这里做错了什么?为什么会出现异常?
更新:
SomeClass.updater
是一个 public static ScheduledExecutorService
。
LogManager
是 org.apache.log4j.LogManager
。
更新2:
按照 BGR 的答案,我直接执行如下操作:
public void contextDestroyed(ServletContextEvent arg0) {
SomeClass.updater.shutdown();
}
并且
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
}
我没有从Log4j中得到异常,但是我收到了以下关于
SomeClass.updater
的异常信息,它是一个public static ScheduledExecutorService
:
为什么会这样呢?这些类已经被垃圾回收了吗?INFO: 非法访问:此Web应用程序实例已停止。无法加载java.util.concurrent.ExecutorService。最终的跟踪堆栈由于为调试目的而抛出错误并尝试终止导致非法访问的线程,因此没有功能影响。Throwable发生:
java.lang.IllegalStateException
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
SomeClass.updater.shutdown();
(而不是在监听器中,因为那时已经太晚了)根据destroy()方法的javadoc,此方法为servlet提供了清理正在持有的任何资源(例如内存、文件句柄、线程)并确保任何持久状态与servlet在内存中的当前状态同步的机会。 - Bruno Griederdestroy()
方法不能保证完全执行。也就是说,Tomcat会调用destroy()
方法,然后很快终止,而不考虑destroy()
是否已经完成。 - Don Cheadle