12 octubre 2012

Timer y TimerTask. Programar tareas. TWF.


Hoy voy a hablar de los programadores de tareas de Java. En concreto las clases Timer y TimerTask.


Hay algo que tengo muy claro: No me gustan los hilos ni la concurrencia, así que todo API / utilidad que me abstraiga de utilizar y tener en cuenta toda esa parafernalia es bien recibida, máxime para cuando es algo que no te tiene que requerir mucho tiempo y (nunca mejor dicho) quedarte bloqueado hasta terminarla.

Así que más adelante, se muestra un ejemplo de cómo manejar Timer y TimerTask para ejecutar una tarea: cada día a la misma hora, para ejecutar cada 'n' horas, o 'n' minutos, para ejecutarla una vez a una hora concreta o ejecutarla una vez pasado un tiempo. Y todo esto Thread-Worry-Free. Maravilloso.


package es.snippetea;

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;

/**
*
* Programador de tareas que muestra el uso de la clase Timer
* junto con objetos de tipo TimerTask. Útiles cuando no puedes lanzar
* ejecuciones bloqueantes y no te quieres liar con concurrencia.
*
* @author icendrero
*/
public class ProgramadorDeTareas {

  //Variables para decision de medida
  public static final int HORAS = 0;
  public static final int MINUTOS = 1;
  public static final int SEGUNDOS = 2;
 
  //Variables para tiempo en milisegundos
  private static long unaHora = 3600000;
  private static long unMinuto = 60000;
  private static long unSegundo = 1000;
 
  /**
  *
  * Esto ejecutará una tarea cada X tiempo hasta que se caiga la JVM
  *
  * @param cantidad
  * @param medida
  */
  public static void ejecutaTareaCadaXTiempo(int cantidad, int medida){
       
        //Primero calculo cada cuanto ha de lanzarse(una hora, dos minutos...)
        long periodo = 0;
        switch (medida) {
              case HORAS:
                    periodo = cantidad*unaHora;
                    break;
              case MINUTOS:
                    periodo = cantidad*unMinuto;
                    break;
              case SEGUNDOS:
                    periodo = cantidad*unSegundo;
                    break;
              default:
                    periodo = -1;
        }
       
        //Si ya tenemos un intervalo, lo lanzamos
        if(periodo!=-1){
              Timer tareaEnIntervalo = new Timer();
             
              //Creamos la tarea
              AccionProgramada accionProgramada = new
                         AccionProgramada("lanzaTareaCadaXTiempo - ");
             
              //La programamos
              tareaEnIntervalo.scheduleAtFixedRate(
                         accionProgramada,
                         Calendar.getInstance().getTime(),
                         periodo);
        }else{
              System.out.println("No se lanzará ninguna tarea.");
        }
  }
 
  /**
  * Metodo que ejecuta una tarea diariamente. La ejecuta inmediatamente
  * (aunque podría añadirse un retardo) y después la ejecutará a la misma
  * hora todos los días.
  *
  * @param hora
  * @param minutos
  */
  public static void ejecutaTareaDiariamente(int hora, int minutos){
        //Crea un nuevo calendario acutal
        Calendar ahoraMismo = new GregorianCalendar();
        int horaAhora = ahoraMismo.get(Calendar.HOUR_OF_DAY);
        int minutosAhora = ahoraMismo.get(Calendar.MINUTE);
       
       
        //Tiempo cuando se va a ejecutar por primera vez (y así repetidamente)
        Calendar horaDeEjecucionDiaria = getHoraEjecucion(hora,minutos);
       
        /*
        * Si la hora que me especifican, es una hora pasada (a lo largo del día,
        * p.ej me pasan como parámetro las 14:50 y son las 17:20)
        */
        if (hora
              //No ejecutar hoy, la primera ejecución será mañana
              horaDeEjecucionDiaria.add(Calendar.DAY_OF_MONTH, 1);
        }
       
        //Cálculo para un día.
        long unDiaEntero = 1000L * 60L * 60L * 24L;
       
        //Creo un nuevo timer y obtengo el directorio de trabajo
        Timer lanzaTareaDiariamente = new Timer();
        AccionProgramada accionProgramada = new AccionProgramada("lanzaTareaDiariamente - ");
       
        //Linea que es la que lanza el proceso que se ejecutará cada día
        lanzaTareaDiariamente.scheduleAtFixedRate(
                    accionProgramada,
                    horaDeEjecucionDiaria.getTime(),
                    unDiaEntero);
  }
 
 
 
  /**
  *
  * Ejecuta una tarea a la hora que le digamos
  *
  * @param hora
  * @param minutos
  */
  public static void ejecutaTareaUnaVezAUnaHora(int hora, int minutos){
        Timer lanzaUnaTarea = new Timer();
        AccionProgramada accionProgramada = new
                    AccionProgramada("lanzaTareaUnaVezAUnaHora - ");
       
        //Esto lo ejecutará una vez a esa hora.
        lanzaUnaTarea.schedule(
                    accionProgramada,
                    getHoraEjecucion(hora,minutos).getTime());
  }
 
  /**
  *
  * Metodo que ejecuta una tarea pasado un tiempo
  *
  * @param cantidad
  * @param medida
  */
  public static void ejecutaTareaPasadoUnTiempo(int cantidad, int medida){
        Timer lanzaUnaTareaRetardo = new Timer();
        AccionProgramada accionProgramada = new AccionProgramada("lanzaTareaPasadoUnTiempo - ");
        //Calculamos el retraso
        long retraso = 0;
        switch (medida) {
              case HORAS:
                    retraso = cantidad*unaHora;
                    break;
              case MINUTOS:
                    retraso = cantidad*unMinuto;
                    break;
              case SEGUNDOS:
                    retraso = cantidad*unSegundo;
                    break;
              default:
                    retraso = -1;
        }
       
        //Si ya tenemos un intervalo, lo lanzamos
        if(retraso!=-1){
              //Esto lo ejecutará una vez pasado ese tiempo.
              lanzaUnaTareaRetardo.schedule(accionProgramada,retraso);
        }else{
              System.out.println("No se lanzará ninguna tarea.");
        }
  }
 
 
  /**
  *
  * Método para obtener el Calendar de una hora en concreto.
  *
  * @param hora
  * @param minutos
  * @return El objeto Calendar.
  */
  private static Calendar getHoraEjecucion(int hora, int minutos){
        Calendar horaDeEjecucionDiaria = new GregorianCalendar();
        horaDeEjecucionDiaria.set(Calendar.HOUR_OF_DAY, hora);
        horaDeEjecucionDiaria.set(Calendar.MINUTE, minutos);
        horaDeEjecucionDiaria.set(Calendar.SECOND, 0);
        horaDeEjecucionDiaria.set(Calendar.MILLISECOND, 0);
        return horaDeEjecucionDiaria;
  }
 
  //Main para probar
  public static void main(String[] args) {
     //Main para probar
  public static void main(String[] args) {
        System.out.println("-------------------------------------");
        System.out.println("Lanzamiento de ejecutaTareaUnaVezAUnaHora"
                    +Calendar.getInstance().getTime());
        ProgramadorDeTareas.ejecutaTareaUnaVezAUnaHora(16, 50);
        System.out.println("-------------------------------------");
        System.out.println("Lanzamiento de ejecutaTareaDiariamente"
                    +Calendar.getInstance().getTime());
        ProgramadorDeTareas.ejecutaTareaDiariamente(16, 50);
        System.out.println("-------------------------------------");
        System.out.println("Lanzamiento de ejecutaTareaPasadoUnTiempo"
                    +Calendar.getInstance().getTime());
        ProgramadorDeTareas.ejecutaTareaPasadoUnTiempo(20, ProgramadorDeTareas.SEGUNDOS);
        System.out.println("-------------------------------------");
        System.out.println("Lanzamiento de ejecutaTareaCadaXTiempo"
                    +Calendar.getInstance().getTime());
        ProgramadorDeTareas.ejecutaTareaCadaXTiempo(1, ProgramadorDeTareas.MINUTOS);
        System.out.println("-------------------------------------");

  }


}

/**
* TimerTask de ejemplo.
* @author icendrero
*/
class AccionProgramada extends TimerTask{

  /*
  * Pequeño bean
  */
  private String nombre;
  public AccionProgramada(String nombre){
        this.nombre = nombre;
  }

  /*
  * Esto es lo que se ejecutará cuando le toque.
  */
  @Override
  public void run() {
        System.out.println(nombre + " se ha ejecutado a las "+Calendar.getInstance().getTime());
  }
}


Resultado:
-------------------------------------
Lanzamiento de ejecutaTareaUnaVezAUnaHoraThu Oct 11 16:49:38 CEST 2012
------------------------------------
Lanzamiento de ejecutaTareaDiariamenteThu Oct 11 16:49:38 CEST 2012
-------------------------------------
Lanzamiento de ejecutaTareaPasadoUnTiempoThu Oct 11 16:49:38 CEST 2012
-------------------------------------
Lanzamiento de ejecutaTareaCadaXTiempoThu Oct 11 16:49:38 CEST 2012
-------------------------------------
lanzaTareaCadaXTiempo -  se ha ejecutado a las Thu Oct 11 16:49:38 CEST 2012
lanzaTareaPasadoUnTiempo -  se ha ejecutado a las Thu Oct 11 16:49:58 CEST 2012
lanzaTareaUnaVezAUnaHora -  se ha ejecutado a las Thu Oct 11 16:50:00 CEST 2012
lanzaTareaDiariamente -  se ha ejecutado a las Thu Oct 11 16:50:00 CEST 2012
lanzaTareaCadaXTiempo -  se ha ejecutado a las Thu Oct 11 16:50:38 CEST 2012
lanzaTareaCadaXTiempo -  se ha ejecutado a las Thu Oct 11 16:51:38 CEST 2012
lanzaTareaCadaXTiempo -  se ha ejecutado a las Thu Oct 11 16:52:38 CEST 2012

1 comentario:

  1. Eh muchas gracias idolo...me sacaste de 3 dias sin hacer nada porque no podia encontrar como programar tareas...muy completo

    ResponderEliminar