Publi

Cancelando y reanudando una tarea con Timer y TimerTask en Java

Hemos estado viendo cómo utilizar TimerTask para programar tareas en el tiempo y cómo pasarle argumentos para hacer una funcionalidad más completa. Ahora vamos a ver cómo podemos cancelar una tarea periódica que ha sido programada (eso es fácil), pero pueden surgir problemas a la hora de reanudar la tarea, para lo cual propongo algunas ideas.

Lo primero, es tener un código básico para lanzar una tarea y cancelarla:
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();
    }
}

En este ejemplo, transcurrido un segundo (con Thread.sleep()), cancelaremos la tarea, por lo tanto no se ejecutará más, aunque el proceso se quedará a la espera, ya que el Timer sigue activo. Podemos hacer “timer.cancel()” y por tanto el proceso terminará. El problema viene cuando queremos que la tarea programada se reanude, ya que tenemos que crear de nuevo el objeto de la tarea, si intentamos aprovechar el objeto task que ya tenemos, nos devolverá una excepción.

Si queremos parar y reanudar tendremos que hacer algo así:
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);
    }
}

Aunque claro, tenemos que definir de nuevo la clase implícita de TimerTask, por lo que estaría bien crear una clase derivada de TimerTask, que parara la tarea y se reanudara ella sola, para ello, nuestra TimerTask (MyTimerTask) debe conocer al timer, así podrá reprogramar la tarea incluso con diferente frecuencia:
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);
    }
}

Pero claro, ahora el problema es que la tarea, una vez cancelada, al tener que crear de nuevo el objeto, si tenemos que pasar información de la tarea antigua a la tarea nueva, simplemente debemos pasar esa información de tarea en tarea, podemos hacer como en el siguiente ejemplo, tener una clase que haga de almacén de información para la tarea, y pasaremos su instancia entre los TimerTasks, para evitar que el proceso lanzador sea capaz de modificar esa información, podemos poner el constructor sobrecargado (donde pasamos además el nuevo objeto) como privado.

En el siguiente ejemplo, sólo metemos un entero en el objeto MyTimerTaskInfo (podemos meter todo lo que queramos mantener entre las programaciones de tareas), y con ese objeto controlaremos la salida del programa en la que se cancelará también el timer cuando se haya programado la tarea unas 5 veces:

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 (no cambia)

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);
    }
}

También podría interesarte...

There are 2 comments left Ir a comentario

  1. Pingback: BlogESfera.com /

  2. Pingback: Cancelando y reanudando una tarea con Timer y TimerTask en Java | PlanetaLibre /

Leave a Reply