Java项目中Timer应用问题分析一例
1.背景
项目中使用Timer来设置一个定时任务,在每天凌晨2点生成一个报告。项目是使用tomcat的一个Web程序。
web程序在tomcat启动时在初始化 servlet时 设置Timer的schedule。
2.问题现象
Timer关联的TimerTask最近有个改动,需要更新代码。代码更新以后,部署web程序,重启tomcat后发现
似乎有两个Timer再跑:修改前的TimerTask代码依然在运行,修改后的代码也在运行。
3.问题分析
项目中 构造 Timer 初始化代码为: Timer task = new Timer();
查询API后发现, Timer的构造函数有以下几种:
Timer() Creates a new timer. Timer(boolean isDaemon) Creates a new timer whose associated thread may be specified to run as a daemon. Timer(String name) Creates a new timer whose associated thread has the specified name. Timer(String name, boolean isDaemon) Creates a new timer whose associated thread has the specified name, and may be specified to run as a daemon.
默认的构造函数: Creates a new timer. The associated thread does not run as a daemon.
表示用来 执行TimerTask的线程是非daemon线程。 我们知道,JVM中如果所有正在运行的线程都是daemon线程,那么JVM将自动退出,即不再继续运行了。
这里,因为是用 new Timer() 构造的 Timer,导致关联的线程是非daemon线程。 于是,在stop tomcat的时候,这个Timer关联的线程还是在继续运行的。
因此,有新旧两个版本的 TimerTask在同时运行。
4.问题分析的验证
1) 使用 ps -ef | grep tomcat 检查 有多少个 tomcat线程
2) 重启tomcat
3) 再次 运行 ps -ef | grep tomcat 发现 果然又多了一个 tomcat线程
5.解决问题
使用 下面的构造函数生成 Timer实例
Timer(String name, boolean isDaemon)
Creates a new timer whose associated thread has the specified name, and may be specified to run as a daemon.
Timer task = new Timer(“My Timer Task”,true)
表示给执行TimerTask的线程起了个名字My Timer Task,这样方便实用 jstack工具时快速的定位到这个线程。
同时,将isDaemon 设置为true,这样在tomcat stop的时候,与之相关的JVM会自动退出,因此所有daemon线程也就不会再运行了。
也就不会出现几个tomcat线程同时运行的情况(其实是执行Tomcat的JVM没有退出,因为还有TimerTask的线程在跑着)。
6. 结论
当构造函数有多个的时候,尽量先搞清楚各个构造函数的区别,以及为什么要有这些不同的构造函数,然后再选择一个合适的构造函数来初始化。
可以使用ScheduledThreadExecutor 来替代Timer。
微信赞赏 支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/java-core/2680.html | 边城网事