我正在尝试在关闭Tomcat时关闭线程
具体来说,我试图关闭log4j看门狗(用于文件更改),我也试图关闭在我的网络应用程序中使用类的执行程序。
关机后,我在Catalina.out中看到例外情况
对于Log4J,我看到:
信息:非法访问:此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)
对于执行者部分:
信息:非法访问:此Web应用程序实例已停止 已经。无法加载com.my.class.SomeClass。最终的 跟踪堆栈跟踪是由调试抛出的错误引起的 目的以及试图终止引起的线程 非法访问,并没有功能影响。发生了可怜的事: 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
UPDATE2:
在听完BGR的答案之后我直接做了
public void contextDestroyed(ServletContextEvent arg0) {
SomeClass.updater.shutdown();
}
和
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
}
我没有从Log4j中获得异常,但我得到SomeClass.updater
public static ScheduledExecutorService
的以下异常:
信息:非法访问:此Web应用程序实例已停止 已经。无法加载java.util.concurrent.ExecutorService。该
最终跟踪堆栈跟踪是由于抛出的错误引起的 调试目的以及尝试终止其中的线程 导致非法访问,并没有任何功能影响。 Throwable的
发生:java.lang.IllegalStateException
在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1587)
在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1546)
为什么呢?这些课程是否已被垃圾收集?
答案 0 :(得分:3)
我会在servlet的init()方法中注册shutdown hooks而不是contextDetroyed(),但无论如何,为什么你首先需要Shutdown钩子?
你不能直接在contextDestroyed()方法中调用SomeClass.updater.shutdown();
吗?
修改强>
监听器的 contextDestroyed()
对于执行程序服务来说是迟到的。正如javadoc 中所述,所有servlet和过滤器都将被销毁 之前,任何ServletContextListeners都会被告知上下文破坏。
而覆盖servlet destroy()
应该没问题,因为根据javadoc 这个方法为servlet提供了清理所有资源的机会(例如,内存,文件句柄, 线程 ...
@Override
public void destroy( ) {
myThreadExecutor.shutdown();
super.destroy( );
}
答案 1 :(得分:2)
致电
LogManager.shutdown();
contextDestroyed()方法中的是第一步,但ExecutorService不会立即关闭。您将获得异常,因为在contextDestroyed()方法返回后,ExecutorService线程仍在运行。你需要这样做:
public void contextDestroyed(ServletContextEvent arg0) {
LogManager.shutdown();
if(LogManager.awaitTermination(10, TimeUnit.SECONDS) == false) {
LogManager.shutdownNow();
}
}
这样,当contextDestroyed()退出时,线程池已关闭并停止所有线程。