2009-03-05 8 views
7

Mi programa tiene un componente, denominado Planificador, que permite que otros componentes registren puntos en el momento en el que desean que se los devuelva. Esto debería funcionar muy parecido al servicio cron de Unix, i. mi. usted le dice al Programador "notifíqueme a las diez minutos después de cada hora completa".Clase de biblioteca Java para manejar la ejecución programada de "devoluciones de llamada"?

Me doy cuenta de que no hay devoluciones de llamada reales en Java.

Aquí está mi enfoque, ¿hay una biblioteca que ya haga esto? No dude en sugerir mejoras, también.

Registro de llamadas a Programador pasa:

  • una especificación de tiempo que contiene la hora, minuto, segundo, mes del año, dom, Dow, donde cada elemento puede ser indeterminado, que significa "ejecutar cada hora/minuto etc. " (al igual que los crontabs)
  • un objeto que contiene datos que le indicarán al objeto que llama qué hacer cuando el Programador lo notifique. El Programador no procesa esta información, solo la almacena y la reenvía luego de la notificación.
  • una referencia al objeto que llama

En el arranque, o después de una nueva solicitud de registro, el programador comienza con un objeto Calendario de la hora actual del sistema y comprueba si hay alguna entrada en la base de datos que coincidan con esta punto en el tiempo. Si los hay, se ejecutan y el proceso comienza de nuevo. Si no lo hay, el tiempo en el objeto Calendario se incrementa en un segundo y los entreis se vuelven a verificar. Esto se repite hasta que haya una entrada o más que coincidan. (Simulación de eventos discretos)

El programador recordará esa marca de tiempo, dormirá y se activará cada segundo para verificar si ya está allí. Si sucede que se despierta y el tiempo ya pasó, comienza de nuevo, del mismo modo si ha llegado el momento y las tareas se han ejecutado.


Editar: Gracias por señalarme a cuarzo. Estoy buscando algo mucho más pequeño, sin embargo.

Respuesta

4

Si sus necesidades son simples, considerar el uso de java.util.Timer:

public class TimerDemo { 

    public static void main(String[] args) { 
    // non-daemon threads prevent termination of VM 
    final boolean isDaemon = false; 
    Timer timer = new Timer(isDaemon); 

    final long threeSeconds = 3 * 1000; 
    final long delay = 0; 
    timer.schedule(new HelloTask(), delay, threeSeconds); 

    Calendar calendar = Calendar.getInstance(); 
    calendar.add(Calendar.MINUTE, 1); 
    Date oneMinuteFromNow = calendar.getTime(); 

    timer.schedule(new KillTask(timer), oneMinuteFromNow); 
    } 

    static class HelloTask extends TimerTask { 
    @Override 
    public void run() { 
     System.out.println("Hello"); 
    } 
    } 

    static class KillTask extends TimerTask { 

    private final Timer timer; 

    public KillTask(Timer timer) { 
     this.timer = timer; 
    } 

    @Override 
    public void run() { 
     System.out.println("Cancelling timer"); 
     timer.cancel(); 
    } 
    } 

} 

Como ha sido noted, el ExecutorService de java.util.concurrent ofrece una API más rica si la necesita.

4

Quartz es la gran y obvia potencia en esta área, pero hay algunas alternativas para explorar.

Cron4j es una biblioteca suficientemente decente, que es un poco más liviana que Quartz. Proporciona buena documentación y hará lo que quiera.

Probablemente más interesante es si desea utilizar una biblioteca que encaja mejor con las bibliotecas de concurrencia de Java (en particular los ejecutores y ScheduledExecutors) entonces HA-JDBC tiene una interfaz CronExecutorService, implementado por su CronThreadPoolExecutor. Ahora, curiosamente, tiene una dependencia en Quartz (para proporcionar la clase CronExpression), pero creo que los dos juntos funcionan mejor que solo Quartz. Si no desea grandes dependencias, es fácil extraer el puñado de clases de Quartz y HA-JDBC que hacen que esto suceda.

Dado que desea algo mucho más pequeño (apenas se da cuenta de su edición), tome CronExpression de Quartz y las dos clases de HA-JDBC que mencioné anteriormente. Eso lo hará.

5

Si sus objetos conocen exactamente los puntos individuales en el tiempo que desean que se ejecuten, entonces podría usar un java.util.concurrent.ScheduledExecutorService. Luego simple llamada:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); 
long timeToExecute = ... //read from DB? use CronTrigger? 
long delayToExecution = timeToExecute - System.currentTimeMillis(); 
scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS); 

Sólo había necesidad de utilizar Quartz si desea que el programador mismo para manejar la funcionalidad como "ejecutar cada 5 segundos", o si desea un comportamiento complejo ejecuciones en torno perdidas, o la persistencia de la pista de auditoría de ejecución.

En realidad, puede volver a utilizar trivialmente la clase CronTrigger de Quartz para obtener un "tiempo de ejecución siguiente". La clase es completamente independiente y no depende de que se invoque desde el Quartz "contexto". Una vez que tenga el siguiente tiempo de ejecución como Date o long, sólo puede utilizar el Java ScheduledExecutorService que el anterior

0

No puedo creer que java.util.Timer haya sido votado como la respuesta. El cuarzo es realmente una opción mucho mejor.

Una gran ventaja de cuarzo sobre java.util.Timer es que con cuarzo los trabajos se pueden almacenar en el db. Como resultado, un jvm puede programar y otro puede ejecutar. También (obviamente) la solicitud sobrevive a través de jvm reinicia.

+0

Sí, pero necesitaba algo realmente simple, sin dependencias adicionales. Tengo persistencia manejada en mi aplicación de todos modos, el programador no lo necesita. Sin embargo, tengo Quartz en mi lista, si necesito más poder más adelante. –

+0

En la versión más reciente, ahora puede agrupar trabajos de Quartz con Terracotta además de una base de datos. –

+1

Es curioso que las funciones de persistencia de Quartz se promocionen como una gran ventaja: en muchos/la mayoría de los casos, son solo un gran PITA. – StaxMan

0

Probablemente más interesante es si desea utilizar una biblioteca que se ajusta mejor a las bibliotecas de concurrencia de Java (en particular los ejecutores y ScheduledExecutors), entonces HA-JDBC tiene una interfaz CronExecutorService, implementadas por su CronThreadPoolExecutor. Ahora, curiosamente, tiene una dependencia en Quartz (para proporcionar la clase CronExpression), pero creo que los dos juntos funcionan mejor que solo Quartz. Si no desea grandes dependencias, es fácil extraer el puñado de clases de Quartz y HA-JDBC que hacen que esto suceda.

Solo quería decir que intenté extraer estas clases, ¡y funcionó! Necesitaba estas tres clases:

  • CronExpression (cuarzo)
  • CronThreadPoolExecutor (ha-JDBC)
  • DaemonThreadFactory (ha-JDBC)

Y yo sólo tenía que hacer estos ajustes menores:

  • Extracción del registrador de CronThreadPoolExecutor (se creó pero nunca utilizado)
  • movido el YEAR_TO_GIVEUP_SCHEDULING_AT constante desde CronTrigger a CronExpression

yo estaba encantada de que no he tenido tirón atrapado en una maraña de dependencias. ¡Felicidades a los autores de la clase!

Y ha estado funcionando como un campeón.

1

Recomiendo encarecidamente cron4j (ya mencionado) sobre Cuarzo, a menos que necesite absolutamente algunas de las características más avanzadas y complejas de Quartz. Cron4j se enfoca muy bien en lo que se supone que debe hacer, tiene una documentación decente y no es una solución de fregadero de cocina.

Cuestiones relacionadas