Analysis and Solution for Timer-0 Thread Not Stopping in Spring Boot Applications

Dec 03, 2025 · Programming · 12 views · 7.8

Keywords: Spring Boot | Thread Pool | Memory Leak

Abstract: This paper examines the warning "Timer-0 thread not stopped" in Spring Boot 1.5.9 applications deployed on Tomcat 9. Based on Q&A data, the issue is traced to the shutdown method of ScheduledThreadPoolExecutor failing to terminate threads promptly. The optimal solution is changing the destroyMethod from shutdown to shutdownNow, ensuring forceful thread termination during application shutdown. The article also discusses Oracle driver deregistration, memory leak risks, and debugging techniques, providing comprehensive technical guidance for developers.

In web applications built with Spring Boot 1.5.9.RELEASE and deployed on Tomcat 9, developers often encounter a warning: "The web application appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak." This warning indicates that background threads are not properly terminated during application shutdown, potentially leading to memory leaks. Based on Q&A data, this article delves into the root cause and presents effective solutions.

Problem Context and Error Log

The developer uses Spring Boot 1.5.9.RELEASE, Java 8, Tomcat 9, Jersey, and an Oracle database. The application configures scheduled tasks via @EnableScheduling and ScheduledTaskRegistrar. The task class ClearCacheJob employs the @Scheduled annotation to clear cache hourly. Additionally, a ServletContextListener is included to deregister the Oracle JDBC driver upon context destruction.

When stopping the Tomcat server, the console outputs the following warning:

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)

The stack trace shows that the Timer-0 thread originates from java.util.TimerThread, indicating that Timer-related threads are not being terminated.

Root Cause Analysis

According to the best answer (Answer 2) in the Q&A data, the core issue lies in the thread pool destruction method configured in the ScheduleConfig class. The original code uses @Bean(destroyMethod = "shutdown"), which invokes the ScheduledThreadPoolExecutor.shutdown() method. This method stops accepting new tasks but allows submitted tasks to complete, potentially leaving threads active during application shutdown and triggering Tomcat's warning.

Other answers provide supplementary insights: Answer 1 notes that placing the Oracle driver in Tomcat's /lib folder instead of /WEB-INF/lib may interfere with thread management; Answer 3 mentions that java.util.Timer might be implicitly created in the code, requiring manual cancellation of its threads; Answer 4 suggests checking Maven build integrity, though it is less relevant to this issue.

Solution: Using the shutdownNow Method

The optimal solution is to modify the ScheduleConfig class by changing the destroyMethod from "shutdown" to "shutdownNow". The revised code is as follows:

@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);
    }
}

The shutdownNow method attempts to stop all active tasks immediately and returns a list of tasks that were awaiting execution. This ensures that the thread pool is forcefully terminated during application context destruction, preventing residual Timer-0 threads. This method is effective for ScheduledThreadPoolExecutor, as Executors.newScheduledThreadPool returns an instance of this executor.

Additional Considerations and Optimization Tips

Beyond the core solution, developers should consider the following aspects to optimize their applications:

Conclusion

The issue of Timer-0 threads not stopping in Spring Boot applications primarily stems from the delayed termination characteristic of ScheduledThreadPoolExecutor.shutdown(). By switching to the shutdownNow method, the thread pool can be forcefully terminated, eliminating Tomcat warnings. Combined with driver management, memory leak prevention, and debugging measures, developers can build more stable web applications. This solution is based on Spring Boot 1.5.9 and Tomcat 9 environments, but the principles apply to similar configurations.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.