Я реализую ServletContextListener , чтобы планировать различные задания на моем сервере приложений (GlassFish 3.1). Я использую contextInitialized()
для планирования повторяющихся задач и contextDestroyed()
для вызова методов очистки, таких как завершение работы c3p0:
public class JobScheduler implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//schedule TimerTasks
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//cancel TimerTasks
//cleanup methods
}
}
Когда я отменяю TimerTask
s, я добавляю логику, которая ждет завершения любых запущенных задач перед продолжением, чтобы убедиться, что ничего не выполняется при очистке ресурсов.
Переходя к моему вопросу: когда я удаляю свое приложение, я вижу одно или два из этих предупреждений, отображаемых в выводе GlassFish:
WARNING: Input stream has been finalized or forced closed without being explicitly closed; stream instantiation reported in following stack trace
java.lang.Throwable
at com.sun.enterprise.loader.ASURLClassLoader$SentinelInputStream.<init>(ASURLClassLoader.java:1230)
at com.sun.enterprise.loader.ASURLClassLoader$InternalJarURLConnection.getInputStream(ASURLClassLoader.java:1338)
at sun.misc.URLClassPath$Loader.getResource(URLClassPath.java:503)
at sun.misc.URLClassPath.getResource(URLClassPath.java:169)
at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at com.google.common.base.FinalizableReferenceQueue$DecoupledLoader.loadFinalizer(FinalizableReferenceQueue.java:228)
at com.google.common.base.FinalizableReferenceQueue.loadFinalizer(FinalizableReferenceQueue.java:155)
at com.google.common.base.FinalizableReferenceQueue.<clinit>(FinalizableReferenceQueue.java:84)
at com.google.common.collect.CustomConcurrentHashMap$QueueHolder.<clinit>(CustomConcurrentHashMap.java:651)
at com.google.common.collect.CustomConcurrentHashMap$WeakValueReference.<init>(CustomConcurrentHashMap.java:1589)
at com.google.common.collect.CustomConcurrentHashMap$Strength$3.referenceValue(CustomConcurrentHashMap.java:322)
at com.google.common.collect.CustomConcurrentHashMap.newValueReference(CustomConcurrentHashMap.java:1731)
at com.google.common.collect.CustomConcurrentHashMap$Segment.setValue(CustomConcurrentHashMap.java:2050)
at com.google.common.collect.CustomConcurrentHashMap$Segment.put(CustomConcurrentHashMap.java:2430)
at com.google.common.collect.CustomConcurrentHashMap.put(CustomConcurrentHashMap.java:3346)
at MyProject.CacheEngine$MyCustomCache$1.apply(CacheEngine.java:244)
at MyProject.CacheEngine$MyCustomCache$1.apply(CacheEngine.java:237)
at com.google.common.collect.ComputingConcurrentHashMap$ComputingValueReference.compute(ComputingConcurrentHashMap.java:316)
at com.google.common.collect.ComputingConcurrentHashMap$ComputingSegment.compute(ComputingConcurrentHashMap.java:140)
at com.google.common.collect.ComputingConcurrentHashMap.apply(ComputingConcurrentHashMap.java:71)
at com.google.common.collect.MapMaker$ComputingMapAdapter.get(MapMaker.java:848)
//stacktrace of the Runnable called by TimerTask, leading up to a call to Guava ComputingMap
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Из того, что я могу сказать, GlassFish жалуется на InputStream
, который никогда не был явно закрыт, который был открыт ClassLoader
для Finalizer
, вызванного одной из моих вычислительных карт, созданных на основе Guava MapMaker
, к которому обращается задача. Обратите внимание, что приведенная выше трассировка стека - это не исключение, а фактическая трассировка от выполняющейся задачи до создания экземпляра потока.
Мне нужна помощь, чтобы понять, почему этот InputStream
остается открытым, хотя я жду завершения всех задач и могу ли я лучше справиться с его очисткой. Похоже, это связано с компьютерными картами Guava, которые вы можете увидеть в трассировке стека.
Обновление: Я получаю те же предупреждения, если использую ScheduledThreadPoolExecutor
вместо TimerTask
Обновление 2: Tumbleweeded