In the previous article, we have seen the usage of Timer and TimerTask using a small real-world problem. Let’s talk more about the same program.

Scheduling a Task

  1. Timer.schedule() method is used for scheduling a task.
  2. This method takes two arguments the first one is an instance of a class which extends the TimerTask class the second argument is the wait time or delay in milliseconds.
  3. Once the wait time is over the timer execute the task.

But how does this work?

  1. The Timer class uses a thread and a priority-based task queue internally.
  2. As soon as we create the timer, they get initialized and the thread starts the execution.
  3. The thread keeps waiting for new tasks in the queue.
  4. Whenever the user schedules a new task by calling the schedule method, this will get added to the queue.
  5. Once a new task is available or an ongoing task is finished, the thread picks up the next task based on some constraints (This is out of scope and we won’t discuss here).
  6. If the task picked up by the thread is qualified for execution, the run() method of task gets called and so it starts the execution.

The qualification check is done by the thread with the help of the priority task queue. The delay time passed here is one of the constraints for this.

This implies that even if you schedule 100 tasks sequentially with different delays or wait times, the order of task execution may vary.

Code

package org.sydlabz.taskgroup;
import java.util.Timer;
import java.util.TimerTask;
/**
* Tutorial demo program for Timer and TimerTask
* @author Seyed Sahil
*/
public class TaskGroup {
private Timer timer;
public TaskGroup(Timer timer) {
this.timer = timer;
// Schedule a series of tasks with different delay.
this.timer.schedule(new SimpleTask("A"), 1000);
this.timer.schedule(new SimpleTask("B"), 5000);
this.timer.schedule(new SimpleTask("C"), 3000);
this.timer.schedule(new SimpleTask("D"), 1500);
this.timer.schedule(new SimpleTask("E"), 10000);
this.timer.schedule(new SimpleTask("F"), 2000);
this.timer.schedule(new SimpleTask("G"), 6000);
this.timer.schedule(new SimpleTask("H"), 3000);
this.timer.schedule(new SimpleTask("I"), 100);
this.timer.schedule(new SimpleTask("J"), 8000);
}
private class SimpleTask extends TimerTask {
private String id;
public SimpleTask(String id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Task " + this.id + " has been completed.");
}
}
public static void main(String[] args) throws InterruptedException {
Timer timer = new Timer();
new TaskGroup(timer);
// Wait for all the tasks to finish.
Thread.sleep(15000);
timer.cancel();
}
}
view raw TaskGroup.java hosted with ❤ by GitHub

Once you run the above program, we can notice that the execution order varies.

Cancelling Timer

  1. When we call cancel() method on the timer, the priority task queue associated with the Timer will be cleared.
  2. If there are any pending tasks they will be ignored.
  3. If the timer is canceled from the scope of a run() method of a task which is currently being executed by this timer thread, it will not stop the task.
  4. This guarantees that the ongoing task execution will get finished before the timer gets canceled.
  5. Calling cancel() on a timer stops the internal thread and so calling it multiple times after the first time has no effect.
@Override
public void run() {
    if (this.id.equals("D")) {
        // Calling cancel() here will remove other pending tasks.
        // But it completes task D.
        timer.cancel();
    }
    System.out.println("Task " + this.id + " has been completed.");
}

Canceling a Task

Yeah, like Timer, we can cancel TimerTask too. Take a look at below lines of code

  1. We can cancel a task that is in pending execution (still in the queue, not picked up by the thread).
  2. Calling cancel() from within the executing task doesn’t stop the execution but prevents the repeated executions, if this task is scheduled for repeated execution.

The below-given scenario doesn’t have any effect.

@Override
public void run() {
    // This doesn't have any effect.
    //if (this.id.equals("B")) {
    //    this.cancel();
    //}
    System.out.println("Task " + this.id + " has been completed.");
}

The below-given scenario is correct

this.timer.schedule(new SimpleTask("D"), 1500);
TimerTask e = new SimpleTask("E");
this.timer.schedule(e, 10000);
e.cancel();
this.timer.schedule(new SimpleTask("F"), 2000);

This will change the task E’s state to canceled and won’t be picked up by the thread.

That’s it. Hope you understood the things we discussed. Please let me know your queries and suggestions šŸ™‚

Happy Coding!

Seyed F