Java Timer

Java Timer

0 Comments

Timer is a utility class as a facility for Threads to schedule tasks for future execution as a background thread. You can use this class to schedule tasks for one-time execution or for repeated execution at a regular interval.

In this post, I’ll explain how to schedule tasks in Java applications using the Timer and TimerTask classes.

Timer and TimerTask

Timer is used with TimerTask, an abstract class which defines the task to be scheduled by Timer. You need to extend TimerTask to create a task that will be scheduled by Timer. Java TimerTask implements the Runnable interface.

Each of the TimerTask is executed sequentially by a Timer object which has a corresponding single background thread. TimerTask objects should complete execution quickly. If a timer task takes too long to complete, it dominates the timer’s task execution thread, which in turn will delay the execution of the subsequent tasks. The tasks will finally accumulate into a queue.

Note: Java Timer object can be shared by multiple threads without any external synchronization.

A TimerTask object remains in one of the following states.

  • VIRGIN: When a task is created, its initial state will be VIRGIN
  • SCHEDULED: Once the task is picked up by Timer for execution, its state is changed to SCHEDULED.
  • EXECUTED: After execution its state becomes EXECUTED.
  • CANCELLED: If we call the cancel() method on a task, the task goes into the CANCELLED state. A task in the CANCELLED state will never be picked up by the Timer for execution.

Scheduling Tasks with Timer

Let’s start coding and use Timer to schedule a TimerTask.

MyTask is a Java class that defines its own task by extending TimerTask.

MyTask.java
package springframework.guru.javatimer.task;

import java.util.Date;
import java.util.TimerTask;

public class MyTask extends TimerTask {
   @Override
   public void run() {
       System.out.println("Start of mytask at " + new Date());
       timeConsumingTask();
       System.out.println("End of mytask at " + new Date());
   }
   public void timeConsumingTask() {
       try {
           Thread.sleep(20000);
       }catch (InterruptedException ex) {
           ex.printStackTrace();
       }
   }
}

To define your own TimerTask you need to override the run() method of TimerTask. Here we have assumed that the task will take 20 seconds to complete.

Next we will schedule the defined task.

Scheduling a Task to Run Once

I have written a JUnit test class to run the task we defined with the help of Timer. If you are new to JUnit, I suggest going through my series of JUnit posts.

The MyTaskTest class is this.

MyTaskTest.java

package springframework.guru.javatimer.task;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.Date;
import java.util.Timer;

public class MyTaskTest {
   MyTask myTask;
   Timer timer;

   @Before
   public void setUp() {
       myTask = new MyTask();
       timer = new Timer(true);
   }

   @After
   public void tearDown() {
       myTask = null;
       timer = null;
   }

   @Test
   public void schedulingTaskOnce() {
       long delay = 1000L;
       timer.schedule(myTask, delay*10);
       System.out.println("MyTask begins!!" + new Date());
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}

In the @Setup method, Timer(true) creates a new Timer whose associated thread can be run as a daemon thread. You can also use the overladed Timer(String name) constructor to create a timer whose thread has the specified name.

In the test case, the timer.schedule() method schedules the TimerTask to execute after a delay of 10,000 ms.

Once the timer schedules the task, the code instructs the timer’s thread to sleep for 60 seconds.

The output on running the tests in IntelliJ is this.
Test Output Scheduling Once

Scheduling a Repeated Task on a Regular Interval

You can use the scheduleAtFixedRate() method of Timer to schedule the TimerTask periodically with a specific interval.

This code snippet schedules the task with a delay of 1000 ms and to repeat after every 500 ms.

@Test
   public void schedulingTaskAtRepeatedInterval() {
       long delay = 1000L;
       long period = 1000L;
       timer.scheduleAtFixedRate(myTask, delay, period);
       System.out.println("MyTask begins and repeats at a specific interval!!" + new Date());
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }

The output on running the tests in IntelliJ is this.

Scheduling a Task to Run Once a Day

Consider you need to schedule a task to run once a day. One approach is to call the scheduleAtFixedRate() method passing the appropriate delay and period parameters like this.

@Test
public void schedulingTaskDaily() {
   long delay = 1000L;
   long period = 1000L * 60L * 60L * 24L;
   timer.scheduleAtFixedRate(myTask, delay, period);
   System.out.println("MyTask begins and repeats every day!!" + new Date());
   try {
       Thread.sleep(30000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
}

The output on running the test in IntelliJ is this.

Another approach is to use the Timer.schedule(TimerTask task, Date firstTime, long period) method.

Cancelling Timer and TimerTask

At times you might need to cancel a running TimerTask. One way is to invoke the cancel() method on the timer. The second way is to call the cancel() method on the thread that runs the TimerTask.

Call cancel() on the Timer if that’s all it is doing. On the other hand, if the timer itself has other tasks which you wish to continue, call the cancel() method on the thread running TimerTask like this.

public void run() {
   System.out.println("Start of mytask at " + new Date());
   timeConsumingTask();
   System.out.println("End of mytask at " + new Date());
   cancel();
}

The test code is this:

@Test
public void checkCancelOfTimerTask() {
   long delay = 1000L;
   long period = 1000L;
   timer.scheduleAtFixedRate(myTask, delay, period);
   System.out.println("MyTask begins and repeats at a specific interval and then cancels!!" + new Date());
   try {
       Thread.sleep(60000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
}

The output on running the tests in IntelliJ is this.

Note that when you call the cancel() method within the run() method of a TimerTask that was invoked by this Timer, it guarantees that the ongoing task will be the last task executed by the Timer. It takes a minute and above to terminate the test since we have given 60 seconds to stop the Timer thread.

On the other hand, the cancel() method on Timer terminates the timer discarding any currently scheduled tasks. The executing thread terminates once the timer is terminated and no more tasks can be scheduled on the cancelled timer.

The test code for calling cancel() on the Timer is this.

@Test
public void checkCancelOnTimerObject() {
   long delay = 1000L;
   long period = 1000L;
   timer.scheduleAtFixedRate(myTask, delay, period);
   System.out.println("MyTask begins and repeats at a specific interval!!" + new Date());
   try {
       Thread.sleep(4000);
   } catch (InterruptedException e) {
       e.printStackTrace();
   }
   timer.cancel();
   System.out.println("Timer cancelled");
}

Here we specify the sleep time for the Timer thread because we are running the code snippet as a JUnit test case. Hence we must call Thread.Sleep(delay*n) to allow the Timer’s thread to run the task before the JUnit test stops executing.

Let us change the sleep time of MyTask to 1 second to check if the timer is cancelled.

public void timeConsumingTask() {
  try {
      Thread.sleep(1000);
  }catch (InterruptedException ex) {
      ex.printStackTrace();
  }
}

The output on running the tests in IntelliJ is this.

Summary

The built-in Timer is adequate for scheduling tasks in small to mid-size Java applications. When you are developing Spring applications, you can also use the TaskExecutor and TaskScheduler interfaces that the Spring Framework brings in.

However, for large-scale enterprise application development using Spring Boot, you need a more comprehensive scheduling solution.

Quartz is one open source job scheduling library with rich enterprise-class features including JTA transactions and clustering. Spring Boot provides the spring-boot-starter-quartz “Starter” to get you quickly up and running with Quartz.

About SFG Contributor

Staff writer account for Spring Framework Guru

    You May Also Like