The Timer class is used in situations where we want to perform time-related activities, such as scheduling a task to run at a specific time or repeating a task at a specific time interval. When we create a timer, we will instruct it on what code to run using a special class called TimerTask. This class implements a method called run, which will define the code that is executed when the Timer is triggered. This code is run on a separate thread from the code that creates the Timer. To implement a Timer, we will start by creating a TimerTask with code to run when the Timer is triggered. The example below demonstrates how we can create a TimerTask that will print “Hello!” each time the Timer is triggered.

import java.util.Timer;
import java.util.TimerTask;

class TimerCode extends TimerTask {
    public void run() {
        System.out.println("Hello!");
    }
}

Once we have our TimerTask implemented, we can set up a Timer to run the task as required.

Timer scheduling

We can schedule a TimerTask to execute using the schedule method of our Timer object. This method has many different modes we can utilize, but to start, we will look at how to schedule a task to run once, at a specific date and time.

Suppose that we have some code we wish to run 2 seconds after the time the program is executed at. To do so, we would need to first get the current date and time, then add 2 seconds to it. Once we have this result, we can schedule our Timer to execute the code at the result. The code below shows how this can be done, using the TimerTask we defined previously.

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerCode();

        LocalDateTime timeToExecute = LocalDateTime.now().plusSeconds(2);
        Date execTime = Date.from(timeToExecute.atZone(ZoneId.systemDefault()).toInstant());
        timer.schedule(task, execTime);
    }
}

In this example, we start by creating a LocalDateTime object, which stores the current time on the user’s system, plus two seconds, to give us a time that is two seconds from the time the application was run at. We then convert it to a Date object so it can be used with the schedule method. When we convert the LocalDateTime into a Date, we specify to use ZoneId.systemDefault(). This will ensure that the Date that is created matches the timezone of the person running the application. The result of this code is that our text “Hello” will print to the screen 2 seconds after the application is run.

Fixed rate scheduling

In the last section, we saw how we could use the schedule method to run a task a single time at a specific time and date. In this section, we will look at how we can create a task that starts at a specific time and date, then repeats on a fixed interval.

There are two ways that we can set up a fixed rate schedule. The first is to specify a delay from when the program starts, then an interval at which the task repeats. For example, if we wanted to start the task 2 seconds after the program begins, and repeat it every 3 seconds, we would use the code shown below.

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerCode();

        timer.schedule(task, 2000, 3000);
    }
}

Note that the schedule method expects time to be provided in milliseconds, so we use 2000 milliseconds to represent 2 seconds, and 3000 milliseconds to represent 3 seconds. If we wanted to start the execution of our code at a specific date and time like before, we can simply add the rate of repeat as a third argument for the schedule method. The code below shows how we can add a fixed rate of 2 seconds to our task.

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerCode();

        LocalDateTime timeToExecute = LocalDateTime.now().plusSeconds(2);
        Date execTime = Date.from(timeToExecute.atZone(ZoneId.systemDefault()).toInstant());
        timer.schedule(task, execTime, 2000);
    }
}

Cancelling and exceptions

Once we schedule a fixed rate TimerTask, we might want to eventually stop it from running. To do this, we can use the cancel method, which will cancel any tasks that a Timer currently has. To do this, we just need to call the cancel method of the TimerTask we wish to stop.

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerCode();

        timer.schedule(task, 2000, 3000);
        task.cancel();
    }
}

We can also use the cancel method on our Timer object in order to cancel all tasks that are associated with the Timer. This is ideal if you wish to cancel multiple tasks at the same time. The following example demonstrates how we can use the cancel method with our Timer object.

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerCode();
        TimerTask task2 = new TimerCode();

        timer.schedule(task2, 0, 2000);
        timer.schedule(task, 0, 1000);
        timer.cancel();
    }
}

In this example, both task and task2 would be stopped as soon as timer.cancel() is called.

In addition to canceling tasks, we also want to consider what happens if a task crashes unexpectedly, due to an exception. If we were to create a TimerTask that throws an exception, we will see that when the exception is thrown, the TimerTask stops running, and our program crashes. Ideally, we would like to be able to recover from an exception if it does occur. To do this, we can wrap our TimerTask code in a try-catch.

class TimerCode extends TimerTask {
    public void run() {
        try {
            throw new IllegalArgumentException();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }
}

When this code throws the exception, it will print the message, then run again at the next scheduled time. This is ideal for situations where we might be looking for an update file that might not exist yet. If the file is not found, we catch the exception and try again later when the file might be available. In some cases, we may want to cancel a TimerTask if it encounters an exception. To do this, we can use the cancel method discussed earlier.

class TimerCode extends TimerTask {
    public void run() {
        try {
            throw new IllegalArgumentException();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            this.cancel();
        }
    }
}

With this code, our TimerTask will now cancel as soon as an exception occurs.

Conclusion

In this topic, we’ve covered the main points on creating and scheduling Timers and TimerTasks, as well as handling exceptions caught within TimerTask code. With this, you now have the knowledge required to apply Timers to your own code!

Leave a Reply

Your email address will not be published.