0

I am trying to build more or less a watchdog class. If a value hasn't changed for a certain time, the class should do something. Therefore I want to utilize a standard timer, the idea is to set a timer, and reset it as soon as the watched value changes.

public class Watchdog {
    public final Timer TIMER = new Timer(true);
    public final long DELAY;
    public Watchdog(long delay){
        DELAY=delay;
        valueChanged();
    }

    public void valueChanged(){
        TIMER.cancel();
        TIMER.purge();
        TIMER.schedule(new TimerTask() {

            @Override
            public void run() {
                Watchdog.this.alarm();
            }
        }, DELAY);
    }

    public void alarm(){
        System.out.println("Watchdog barked");
    }
}

Unfortunately I get an IllegalStateException every time I call TIMER.cancel(), as there is no timer set at the first call. What am I doing wrong? How to reset the timer, even if there is no timer set?

EDIT Stacktrace

Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:397)
at java.util.Timer.schedule(Timer.java:193)
at deleteme.Watchdog.valueChanged(Watchdog.java:28)
at deleteme.Watchdog.<init>(Watchdog.java:22)
at deleteme.Deleteme.main(Deleteme.java:19)
Java Result: 1
gorootde
  • 4,003
  • 4
  • 41
  • 83
  • possible duplicate of [restart timer in java](http://stackoverflow.com/questions/10335784/restart-timer-in-java) – Sachin Verma Apr 03 '14 at 08:12
  • No duplicate, as my question is about how to call cancel WITHOUT setting some kind of "Dummy" TimerTask. (Thats exactly what the solution in the other question uses. – gorootde Apr 03 '14 at 08:16
  • Is it possible to see full stackTrace? – Guy Bouallet Apr 03 '14 at 08:19
  • Have you thought avec using ScheduledThreadPoolExecutor which seems to be more appropriate for your use can than Timer according to: http://stackoverflow.com/questions/32001/resettable-java-timer Note that the link contains sample code for using Timer also. – Guy Bouallet Apr 03 '14 at 08:36
  • @GuyBouallet I've added the stacktrace. The solution in the thread you mentioned works. Of course I can build a class which does that on it's own. But as util.Timer does already implement this behaviour, I'd like to stick to that. – gorootde Apr 03 '14 at 08:59

1 Answers1

1

According to the Timer source code, the cancel method changes the value of an internal flag called newTasksMayBeScheduled to false.

public void cancel() {
    synchronized(queue) {
        thread.newTasksMayBeScheduled = false;
        queue.clear();
        queue.notify();  // In case queue was already empty.
    }
}

The value of this flag is checked prior to scheduling a new task and it fires the exception you get as it is false.

if (!thread.newTasksMayBeScheduled)
            throw new IllegalStateException("Timer already cancelled.");

I think that you should use the cancel method of the TimerTask instead of Timer. For the sake of completeness of the answer, note that an alternative would be to use ScheduledThreadPoolExecutor.

Guy Bouallet
  • 2,099
  • 11
  • 16