Web应用程序似乎已启动名为[Timer-0]的线程但未能将其停止

Mah*_*leh 23 java multithreading tomcat spring-boot

我正在使用springboot 1.5.9.RELEASE + Java 8 + tomcat 9 + Jersey + Oracle和我的应用程序已安排的方法定义如下:

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}
Run Code Online (Sandbox Code Playgroud)

工作班:

@Component
public class ClearCacheJob {



    @Scheduled(fixedRate = 3600000, initialDelay = 10000)
    public void clearErrorCodesCache() {
        try {
            logger.info("######## ClearCacheJob #########");
        } catch (Exception e) {
            logger.error("Exception in ClearCacheJob", e);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我也有一个类来取消注册oracle驱动程序,如下所示:

@WebListener
public class ContainerContextClosedHandler implements ServletContextListener {

    private static final Logger logger = LoggerFactory.getLogger(ContainerContextClosedHandler.class);

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        logger.info("######### contextInitialized #########");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        logger.info("######### contextDestroyed #########");
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("deregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error deregistering driver %s", driver), e);
            }

        }
    }

}
Run Code Online (Sandbox Code Playgroud)

但是当停止tomcat时,我收到以下错误:

WARNING [Thread-11] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [hai] 
appears to have started a thread named [Timer-0] but has failed to stop it. 
 This is very likely to create a memory leak. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 java.lang.Object.wait(Unknown Source)
 java.util.TimerThread.mainLoop(Unknown Source)
 java.util.TimerThread.run(Unknown Source)
Run Code Online (Sandbox Code Playgroud)

请告知我为什么会收到此错误以及如何解决此问题,谢谢.

Sky*_*ker 7

我想与此问题的根本原因分析分享一些解决方案。

对于 Oracle 用户:

解决方案#1:

您应该从 Tomcat 的/lib文件夹中删除您的 Oracle 驱动程序。我遇到了同样的问题,它得到了解决。

注意:让 oracle 驱动程序在/WEB-INF/lib文件夹中。

解决方案#2:

您可以通过休眠线程使用真正的 hack。

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
    logger.info("######### contextDestroyed #########");
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        try {
            DriverManager.deregisterDriver(driver);
            logger.info(String.format("deregistering jdbc driver: %s", driver));
        } catch (SQLException e) {
            logger.info(String.format("Error deregistering driver %s", driver), e);
        }
    }
    try { Thread.sleep(2000L); } catch (Exception e) {} // Use this thread sleep
}
Run Code Online (Sandbox Code Playgroud)

资源链接: “Tomcat无法停止[Abandoned connection cleanup thread]”的解决方法

解决方案#3:

Svetlin Zarev说没有什么可担心的。这是tomcat的标准消息。他给出了如下根本原因分析:

当应用程序已启动 ScheduledExecutor(但任何其他线程/TheadPool 都会发生这种情况)并且没有在 contextDestroyed 时将其关闭时,就会发生此问题。因此,请检查您是否在应用程序/服务器停止时关闭线程。

资源链接: Tomcat8内存泄漏

解决方案#4:

对于Oracle用户,这篇文章有多个答案:为了防止内存泄漏,JDBC驱动程序已被强行注销


对于 MySQL 用户,

解决方案#5:

带解决方案的根本原因分析:

NonRegisteringDriver类中废弃连接的清理线程 被重构为具有静态关闭方法。内存已分配但从未释放。如果您遇到此泄漏问题,AbandonedConnectionCleanupThread.shutdown() 请使用contextDestroyed方法中的调用在您的应用程序中实现上下文侦听器。

此问题在 Tomcat 应用程序服务器下运行的应用程序中发现,但它可能也适用于其他应用程序服务器。

例如:

@WebListener
public class YourThreadsListener implements ServletContextListener {
   public void contextDestroyed(ServletContextEvent arg0) {
      try {
          AbandonedConnectionCleanupThread.shutdown();
      } catch (InterruptedException e) {
      }
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果容器不支持注释,则将描述添加到 web.xml:

<listener>
    <listener-class>user.package.YourThreadsListener</listener-class> 
</listener>
Run Code Online (Sandbox Code Playgroud)

资源链接: https : //docs.oracle.com/cd/E17952_01/connector-j-relnotes-en/news-5-1-23.html


sha*_*zin 5

更改您ScheduleConfig的使用shutdownNow而不是shutdown破坏方法.

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdownNow")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

30437 次

最近记录:

5 年,10 月 前