Home > Java > Canceling and resume tasks with Timer and TimerTask in Java

Canceling and resume tasks with Timer and TimerTask in Java

We’ve been talking about using TimerTask and Timer to schedule tasks and passing arguments to these tasks for a more complex functionality. Today, we’ll be cancelling these periodic tasks (easy), but there are some problems when resuming, so I propose some ideas.

First, here is a basic code to cancel a task:
TimerEx.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.Timer;
import java.util.TimerTask;

class TimerEx
{
    public static void main(String arglist[])
    {
    Timer timer;
    timer = new Timer();

    TimerTask task = new TimerTask()
        {
        int tic = 0;

        @Override
        public void run()
        {
            System.out.println((tic++%2==0)?"TIC":"TOC");
        }
        };

    timer.schedule(task, 10, 100);
    try
        {
        Thread.sleep(1000);
        }
    catch (Exception e)
        {
        }
    task.cancel();
    }
}

In this example, the main program waits for a second (with Thread.sleep()) while the tasks is scheduled, so we will see the output running, and after that second, the process stops, but not exits because the Timer is still active. We can write “timer.cancel()”, the task is cancelling too and the program exists.

The problem comes when resumin this task after a while, because we have to create the TimerTask object again, if we try to reuse the old TimerTask (task) created, we’ll get an exception.

So, to cancel and resume, we can do it like this:
TimerEx.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import java.util.Timer;
import java.util.TimerTask;

class TimerEx
{
    public static void main(String arglist[])
    {
    Timer timer;
    timer = new Timer();

    TimerTask task = new TimerTask()
        {
        int tic = 0;

        @Override
        public void run()
        {
            System.out.println((tic++%2==0)?"TIC":"TOC");
        }
        };

    timer.schedule(task, 10, 100);
    try
        {
        Thread.sleep(1000);
        task.cancel();
        Thread.sleep(1000);
        }
    catch (Exception e)
        {
        }

    task = new TimerTask()
        {
        int tic = 0;

        @Override
        public void run()
        {
            System.out.println((tic++%2==0)?"TIC2":"TOC2");
        }
        };

    timer.schedule(task, 10, 100);
    }
}

But, as we must define the inner TimerTask class again, it’s interesting to create a separate derivate class. But let’s go further, we’ll make a TimerTask derivate that cancels and resumes itself, so our TimerTask (MyTimerTask) must know the Timer object, this way it can also re-schedule the task at different frequencies:

MyTimerTask.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.Timer;
import java.util.TimerTask;

class MyTimerTask extends TimerTask
{
    private int tic=0;
    private Timer timer;

    public MyTimerTask(Timer t)
    {
    this.timer = t;
    }

    public void run()
    {
    System.out.println((tic++%2==0)?"TIC":"TOC");
    if (tic%10==0)
        {
        System.out.println("Cancelling task");
        this.cancel();
        this.timer.schedule(new MyTimerTask(this.timer), 1000, 1000);
        }
    }
}

TimerEx.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.Timer;
import java.util.TimerTask;

class TimerEx
{
    public static void main(String arglist[])
    {
    Timer timer;
    timer = new Timer();

    TimerTask task = new MyTimerTask(timer);
    timer.schedule(task, 10, 100);
    }
}

But, as we can see, we must re-create the task object when re-scheduling, what about passing information between the old task to the new task? We may want that, for example, to know what has happened before the new task is created. To do that, we can create a store class, where we can use the attributes to store useful information between schedules, and we can pass this variable to our MyTimerTask constructor, but to avoid external classes to modify the values of our store class, this new overloaded constructor can be private.

In the next example, we just store an integer (we can store as many things as we want), and with this object we will control the times the task was canceled, and make it exit after 5 times:
MyTimerTaskInfo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyTimerTaskInfo
{
    private int times = 0;

    public void setTimes(int newTimes)
    {
    this.times = newTimes;
    }

    public int getTimes()
    {
    return this.times;
    }

    public void increment()
    {
    this.times++;
    }
}

MyTimerTask.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.Timer;
import java.util.TimerTask;

class MyTimerTask extends TimerTask
{
    private int tic=0;
    private Timer timer;
    private MyTimerTaskInfo info;

    public MyTimerTask(Timer t)
    {
    this.timer = t;
    this.info = new MyTimerTaskInfo();
    }

    private MyTimerTask(Timer t, MyTimerTaskInfo i)
    {
    this.timer = t;
    this.info = i;
    }

    public void run()
    {
    System.out.println((tic++%2==0)?"TIC":"TOC");
    if (tic%10==0)
        {
        System.out.println("Cancelling task");
        this.cancel();
        this.info.increment();
        if (info.getTimes()==5)
            {
            System.out.println("Exiting...");
            this.timer.cancel();
            }
        else
            this.timer.schedule(new MyTimerTask(this.timer, this.info), 200, 100);
        }
    }
}

TimerEx.java (not changed)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.util.Timer;
import java.util.TimerTask;

class TimerEx
{
    public static void main(String arglist[])
    {
    Timer timer;
    timer = new Timer();

    TimerTask task = new MyTimerTask(timer);
    timer.schedule(task, 10, 100);
    }
}
  1. No comments yet.
  1. No trackbacks yet.

Top