在Java中不断地将计时器(Timer)和计时器任务(TimerTask)设为null并重新创建

5
我知道使用Timer和TimerTask不再是当前被接受的做法(一些人建议使用线程,其他人建议使用ScheduledExecutorService或其变体),因此这个问题不是关于良好编程实践,而是关于实际错误或异常的可能性。
基本上,我有一个servlet,它保持一个运行中的计数器(这是一个静态日历对象),每秒钟增加一次。当达到指定的截止时间时(默认为10分钟),我从我的应用程序向NIST时间服务器发出调用以获取当前时间,然后将其用于重新设置我的计数器。
相同的TimerTask定义的方法会每秒钟增加一次计数器,也必须在每次我向NIST服务器发出调用(每10分钟)时暂停并重新安排。我尝试在调用NIST服务器之前取消/暂停现有的Timer/TimerTask对象,并在调用之后重新安排TimerTask,但没有成功。
从这个过程中产生的异常在这里描述: 当需要多次设置和取消时,如何在Java中使用计时器? 可以说,无论是TimerTask还是Timer都不能被多次调度,即使使用purge()或cancel()也只能将这些对象设置为Java垃圾回收的候选对象。
使用wait()和notify()会导致同步异常,而我不幸的是没有时间去解决,因此我的线程实验最初失败了。
最终我做的事情是:
secondTickerTask.cancel();
secondTicker.purge();
secondTicker.cancel();

secondTickerTask = null;
secondTicker = null;

Date newCurrentTime = getNistTimeFromFirstWorkingServer();

// Save new date to current time, reset second counter.
setCurrentTimeAndDeadline(newCurrentTime);
startSecondIncrementTimer(newCurrentTime);

secondTicker = new Timer();
secondTickerTask = new TimerTask(){
    public void run(){
        incrementCurrentTimeAndTestDeadline();
    }

我已经在几个晚上以10分钟和1分钟的间隔在NIST服务器调用之间运行了这段代码,并且它运行得很顺畅。

所以,在长时间的引言之后(感谢您的耐心等待),我的问题是:如果我继续使用当前的代码,是否会在长期内造成任何损害?如果我在一个月或六个月的时间内不断制作新的TimerTask和Timer对象,同时将旧的对象置空,那么是否会导致服务器内存不足?Java的垃圾回收机制是否足够强大,能够处理这种使用方式?是否会发生其他可怕的事情?

非常感谢您的时间, - Eli


我的经验是,频繁创建计时器任务没有问题。我们曾经遇到过类似的情况。 - kosa
Java的垃圾回收机制非常强大,只要incrementCurrentTimeAndTestDeadline本身没有积累资源(您没有展示实现),您就不会有问题。就垃圾回收而言,您的情况非常基础,尽管您确实可以在自己的测试中观察到这一点(记录随时间变化的已使用堆空间并观察,参见Runtime类)。 - Jason C
谢谢你们的意见,大家辛苦了。非常感激 =)。这些都是很好知道的东西。我一定会研究Runtime,并且会三次检查我的其他代码是否在某个时刻变得可回收。 - justian17
1个回答

2

Java可以很好地处理计时器任务的创建和放弃。您需要确保在完成计时器操作后丢弃所有对其的引用,这似乎是您正在做的,然后当GC运行时,它将清理计时器引入的任何垃圾。

您是安全的。

请注意,长时间运行的一些Java进程往往会不断分配内存,直到达到其-Xmx限制。这并不意味着存在问题(因为该空间将由GC重新使用),但这也意味着,如果您希望长时间运行的Java进程具有相对较小的占用空间,则不应指定比实际所需大得多的-Xmx


谢谢你的快速回复,rolfl =)。知道我是安全的真是一种解脱。我也会更深入地研究-Xmx。 - justian17

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接