Java EE TimerService创建定时任务异常:周期不符(Wildfly 16)
解决Wildfly 16中Java EE TimerService触发频率异常的问题
这个问题在Wildfly 16里挺常见的,我来帮你分析下可能的原因和解决办法:
核心现象分析
你的定时器触发频率远高于预期,甚至单动作定时器变成周期性触发,这大概率是多个定时器实例同时在运行,而非单个定时器的周期配置错误。
1. 检查Singleton Bean是否被多次实例化
虽然你用了@Singleton和@Startup注解,但Wildfly在热部署、类加载异常等场景下,可能会重复实例化这个Bean,每个实例都会创建独立的定时器,叠加后就会让触发间隔变短。
验证方法:在initialize和programmaticTimout方法中打印当前实例的哈希码:
@PostConstruct public void initialize() { this.timerService.createTimer(0, 5000, null); System.out.println("AutomaticBean.initialize() - Instance Hash: " + this.hashCode()); } @Timeout public void programmaticTimout(Timer timer) { System.out.println("AutomaticBean.programmaticTimout() - Instance Hash: " + this.hashCode()); }
如果输出的哈希码不一致,说明确实存在多个Bean实例,需要排查部署或类加载的问题。
2. 主动清理旧定时器避免残留
Wildfly默认会持久化EJB定时器(默认存储在嵌入式H2数据库或本地文件中),如果应用重新部署但旧定时器未被取消,容器会重新激活这些旧定时器,加上新创建的定时器,就会出现多实例并发触发的情况。
解决办法:给Singleton Bean添加@PreDestroy方法,在应用停止/卸载时主动取消所有定时器:
@PreDestroy public void cleanupTimers() { for (Timer timer : timerService.getTimers()) { timer.cancel(); System.out.println("Cancelled existing timer: " + timer.getId()); } }
这样每次应用停止时,所有由该Bean创建的定时器都会被清理,避免残留。
3. 排查重复的Timer Bean或多应用部署
注意到你的日志里出现的是AutomaticResendBean,但代码类名是AutomaticBean——如果这是两个独立的Timer Bean类,每个都会创建自己的定时器,自然会导致触发频率翻倍。另外也要确认应用是否被重复部署(比如同一个WAR包部署了多个实例)。
4. 清理Wildfly的定时器持久化存储
如果上述方法无效,可以手动清理Wildfly的定时器持久化数据:
- 找到Wildfly的
standalone/data/timer-service-data目录,删除其中的所有文件; - 若使用数据库持久化(比如默认的H2),可以连接数据库删除
EJB_TIMER相关表的所有数据,彻底清除旧定时器残留。
内容的提问来源于stack exchange,提问作者Stefan S.




