Publi

Introducción a Timer y TimerTask en Java.

Los timers son una herramienta muy útil para lanzar una tarea cada cierto tiempo, por ejemplo, si estamos conectados a un servidor, podemos enviar información de estado para no desconectarnos, o lanzar una tarea a una hora determinada, o incluso puede servir para crear una animación (ya que con el tiempo va variando aquello que hayamos dibujado, o va cambiando el fotograma).
El ejemplo más sencillo de un timer puede ser lo siguiente:

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
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()
        {
            if (tic%2==0)
            System.out.println("TIC");
            else
            System.out.println("TOC");
            tic++;
        }
        };
        // Empezamos dentro de 10ms y luego lanzamos la tarea cada 1000ms
    timer.schedule(task, 10, 1000);
    }
}

La salida de este programa será un TIC / TOC alternativamente cada segundo por la consola, ya que la tarea la programamos cada 1000ms. Es extremadamente fácil, en principio tenemos que crear un objeto TimerTask que defina la tarea que vamos a ejecutar dentro de su método run() (el cuál tenemos que invalidar por uno nuestro (con @Override). Luego cargaremos un Timer, y con su método schedule llamaremos a la tarea, indicándole el tiempo que debe esperar para empezar y el tiempo tras el cuál repetirá la tarea de forma indefinida.

Si sólo indicamos un argument, la tarea se ejecutará una sola vez dentro de N milisegundos. También se pueden especificar objectos de tipo Date por argumentos.

Por otro lado, cabe mencionar que junto con schedule() tenemos otro método, scheduleAtFixedRate, la diferencia es que si ocurren retrasos en la ejecución de las tareas, por ejemplo, que esté nuestra aplicación haciendo otras cosas y en lugar de 1000ms, en una de las ejecuciones se tarden 1500, la tarea se ejecutará a los 500ms para compensar. Si el retraso es más grande, se ejecutará varias veces hasta recuperar el ritmo. schedule(), si se retrasa no hará nada, dentro de 1000ms volverá a ejecutar de nuevo la tarea.

Hemos visto que el TimerTask lo he creado de forma implícita, para un ejemplo, o para algo sencillo lo podemos hacer sin miedo. Si ya tenemos una tarea más grande y compleja, lo suyo sería crear una clase que extienda TimerTask para esa tarea, pero eso ya lo veremos más adelante.

Algo interesante que podemos hacer es llamar a una variable externa, es decir, desde nuestro TimerTask, llamar a un atributo de TimerEx, aunque no tiene nada que ver con cómo se hacen los Timers es algo curioso, que a lo mejor produce un pequeño calentamiento de cabeza.
Y es que a lo mejor queremos acceder a ese atributo, es decir, utilizar algo que está fuera del TimerTask

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
import java.util.Timer;
import java.util.TimerTask;

class TimerEx {
    public static void main(String arglist[]) {
    Timer timer;
    timer = new Timer();
    final String str = new String("REACHED TEN TICS");

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

        @Override
        public void run()
        {
            if (tic%2==0)
            System.out.println("TIC");
            else
            System.out.println("TOC");
            tic++;
            if (tic%10==0)
            {
                System.out.println(str);
            }
        }
        };

    timer.schedule(task, 0, 1000);
    }
}

Con este ejemplo, cuando hayamos llamado a la tarea 10 veces, se imprimirá en pantalla la cadena str. Vamos, que desde estas clases anidadas o implícitas, podemos acceder a atributos declarados fuera de los mismos, aunque al ser final no podremos escribir en ellos. De todas formas, al ser objetos podemos crear una clase que sí nos permita modificar datos de la misma. Imaginemos si queremos sacar el atributo tic fuera del TimerTask, para ello debemos crear una clase nueva TicClass y modificar ligeramente el código de TimerEx:

TicClass.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
class TicClass
{
    private int value;

    public TicClass(int initialValue)
    {
    this.value=initialValue;
    }

    public TicClass()
    {
    this.value=0;
    }

    public void setValue(int newValue)
    {
    this.value=newValue;
    }

    public int getValue()
    {
    return this.value;
    }

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

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
import java.util.Timer;
import java.util.TimerTask;

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

    TimerTask task = new TimerTask() {
        @Override
        public void run()
        {
            if (tic.getValue()%2==0)
            System.out.println("TIC");
            else
            System.out.println("TOC");

            tic.increment();

            if (tic.getValue()%10==0)
            {
                System.out.println("TEN TICS!");
            }
        }
        };

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

Con esta idea, podemos hacer una clase colección de varios objetos que queramos modificar durante el transcurso del TimerTask y pasarlo como variable final.

Foto: Andy Roberts (Flickr) CC-by

También podría interesarte...

There are 11 comments left Ir a comentario

  1. Pingback: BlogESfera.com /

  2. Pingback: Pasando argumentos a un TimerTask en Java | Poesía Binaria /

  3. Pingback: Cancelando y reanudando una tarea con Timer y TimerTask en Java | Poesía Binaria /

  4. PROGRAMADOR JAVA /
    Usando Google Chrome Google Chrome 30.0.1599.101 en Windows Windows 7

    excelente APORTE gracias.

    1. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 40.0 en Ubuntu Linux Ubuntu Linux

      Gracias a ti !

  5. Cheko /
    Usando Mozilla Firefox Mozilla Firefox 43.0 en Windows Windows 7

    Buen Aporte Me Sirvio Mucho Gracias… Pero Si Aun Me Puedes Ayudar Un Poco Mas Podrias Decirme Como Podria Modificar Un Label Despues De Cierto Tiempo En JavaFx, Es Decir Cuando Termine Una Animacion Que Dura Cierto Tiempo, Tenia Pensado Hacerlo Con Timer Pero No Me Queda…

    1. Gaspar Fernández / Post Author
      Usando Mozilla Firefox Mozilla Firefox 43.0 en Ubuntu Linux Ubuntu Linux

      Lo siento, no me he metido con JavaFx, ahora estoy más centrado en otras tecnologías. Pero tal vez algún usuario pueda ayudarte. Y si encuentras solución te agradecería que nos dieras un post, o una pista de cómo lo has conseguido. Tal vez puedas ayudar a otro usuario.

  6. Pingback: Un buen 2015 para el blog. Los posts que han marcado el año y consultas SQL – Poesía Binaria /

  7. julian garzón /
    Usando Google Chrome Google Chrome 57.0.2987.133 en Windows Windows 7

    Saludos,
    tengo una aplicación en la que tuve que añadir un método con un timer que consiste en que pasados x horas la aplicación se desconecte del servidor.
    Funciona bien pero a medida que se usa la aplicación el timer cuenta más rápido los segundos, es decir que es inexacto por ejemplo lo pongo a 5 minutos y a los 3 minutos y medio se ejecuta.

  8. Valero /
    Usando Google Chrome Google Chrome 48.0.2564.109 en Windows Windows 7

    Una pregunta, Que funcion desempeña el “%2” que se encuentra en la sentencia if

    1. Gaspar Fernández /
      Usando Mozilla Firefox Mozilla Firefox 55.0 en Ubuntu Linux Ubuntu Linux

      Hola,
      % es el operador módulo, o lo que es lo mismo saca el resto de la división. Cuando ponemos “tic%2” estamos sacando el resto de la división del número que hay en “tic” entre 2. Es más, cuando un número dividido entre 2 da de resto 0, el número tic, es un número par.

      Saludos

Leave a Reply