项目中用Timer做了定时任务,就是每天定时给某些特定的用户发送消息,可是不知道为什么,数据库中老是出现多条通知的情况,我刚开始是这样用Timer类的:
在监听器初始化中给这个Timer添加定时任务,然后就什么都不管了,结果就出现上面的情况,代码如下:
public class JobListener implements ServletContextListener { //执行任务 private Timer timer = new Timer(); public void contextInitialized(ServletContextEvent arg0) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date timerDate = sdf2.parse(sdf.format(new Date())+" 18:00:00"); if(date.after(timerDate)) { //今天18点过后 Calendar calendar = Calendar.getInstance(); calendar.setTime(timerDate); calendar.add(Calendar.DATE, 1); timerDate = calendar.getTime(); } RemindBalanceTask rbt = new RemindBalanceTask(userService, notificationService); timer.schedule(rbt, timerDate, (long)(24*60*60*1000)); System.out.println("添加了一个任务"); } catch (ParseException e) { e.printStackTrace(); } } } public void contextDestroyed(ServletContextEvent sce) { System.out.println("监听器销毁了~~~~~~~~~~~~~~~~~~~~~~~~~"); } }
RemindBalanceTask 这个是执行代码的线程。
今天分析了一下可能出现了原因,分析到了项目会重启,然后监听器被再次初始化,这个时候定时任务的timer还在运行。于是就做了一个实验:
public class TestTimer extends TimerTask{ @Override public void run() { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("我被运行了:"+dateFormat.format(new Date())); } } public class Main { private Timer timer = new Timer(); public static void main(String[] args) { Main main = new Main(); main.timer.schedule(new TestTimer(), new Date(),1000); System.out.println("测试"); main.timer = null; } }
测试结果出来了,出了main方法,照样打印,也就是即使把timer指向null了这个时候计划的任务仍然在运行,于是就改变了代码:
public class Main { private Timer timer = new Timer(); public static void main(String[] args) { Main main = new Main(); main.timer.schedule(new TestTimer(), new Date(),1000); System.out.println("测试"); main.timer.cancel(); } }
这个时候跳出了main方法也就不打印了,哈哈,这下子项目中的问题就出现了,如果是多次重启项目而不是服务器的话,也就是监听器会被多次的重启,但是Timer始终不会消失,重启一次就多了一个Timer,这就是原因了,最后在监听器的销毁的方法中添加了this.timer.cancel();//销毁的时候把这个任务取消,否者这个任务会一直存在这句代码。每次监听器销毁的时候也把这个定时任务给取消。