Clase de biblioteca Java para manejar la ejecución programada de & # 8220; devoluciones de llamada & # 8221 ;?

StackOverflow https://stackoverflow.com/questions/614257

Pregunta

Mi programa tiene un componente, denominado Programador, que permite que otros componentes registren los puntos en el tiempo en que desean que se les devuelva la llamada. Esto debería funcionar como el servicio cron de Unix, i. mi. usted le dice al Programador "notifíqueme cada diez minutos después de cada hora completa".

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

Aquí está mi enfoque, ¿hay una biblioteca que ya haga esto? Siéntase libre de sugerir mejoras también.

Registrar llamada a pases del Programador:

  • una especificación de tiempo que contiene hora, minuto, segundo, año mes, dom, dow, donde cada elemento puede no estar especificado, lo que significa "ejecutarlo cada hora / minuto, etc." (al igual que 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 estos datos, solo los almacena y los devuelve al momento de la notificación.
  • una referencia al objeto que llama

Al inicio, 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 entradas en la base de datos que coincidan con este punto en el tiempo. Si los hay, se ejecutan y el proceso comienza de nuevo. Si no hay, el tiempo en el objeto de Calendario se incrementa en un segundo y se comprueban las entradas. Esto se repite hasta que haya una entrada o más que coincidan (es). (Simulación discreta de eventos)

El Programador recordará esa marca de tiempo, dormirá y se despertará cada segundo para verificar si ya está allí. Si sucede que se despierta y el tiempo ya ha pasado, comienza de nuevo, de la misma manera si ha llegado el momento y los trabajos se han ejecutado.


Editar : Gracias por indicarme Quartz. Sin embargo, estoy buscando algo mucho más pequeño.

¿Fue útil?

Solución

Si sus necesidades son simples, considere usar 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 se ha anotado , el ExecutorService de < a href = "http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-frame.html" rel = "nofollow noreferrer"> java.util.concurrent ofrece una API más rica si la necesita.

Otros consejos

Lookup Quartz

Si sus objetos conocen exactamente los puntos individuales en el tiempo que desean ser ejecutados, entonces puede usar un java.util.concurrent.ScheduledExecutorService . Luego simplemente llaman:

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

Solo necesitaría usar Quartz si desea que el programador maneje funcionalidades como " ejecute cada 5 segundos " La pista de auditoría de ejecución.

Realmente puedes reutilizar de forma trivial la clase CronTrigger de Quartz para obtener un " próximo tiempo de ejecución " ;. La clase es completamente independiente y no depende de ser invocada desde el Quartz " contexto " Una vez que tenga el siguiente tiempo de ejecución como Date o long , puede usar Java ScheduledExecutorService como se indica arriba

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

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

Probablemente, lo más interesante es si desea utilizar una biblioteca que se adapte mejor a las bibliotecas de concurrencia de Java (especialmente Ejecutores y Programadores Ejecutivos), entonces HA-JDBC tiene un Interfaz CronExecutorService , implementada por su CronThreadPoolExecutor . Ahora, curiosamente, tiene una dependencia de Quartz (para proporcionar la clase CronExpression), pero creo que los dos juntos funcionan mejor que solo Quartz solo. Si no desea grandes dependencias, es fácil extraer un puñado de clases de Quartz y HA-JDBC que hacen que esto suceda.

Como quieres algo mucho más pequeño (acabo de notar tu edición), toma CronExpression de Quartz y las dos clases HA-JDBC que mencioné anteriormente. Eso lo hará.

Recomiendo encarecidamente cron4j (ya mencionado) sobre Quartz, a menos que sea absolutamente necesario 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 para el fregadero de la cocina.

El programador de cuarzo generalmente se recomienda.

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 la base de datos. Como resultado, un jvm puede programar y otro puede ejecutar. Además (obviamente) la solicitud sobrevive a través de los reinicios de jvm.

  

Probablemente sea más interesante si desea utilizar una biblioteca que se ajuste mejor a las bibliotecas de concurrencia de Java (particularmente Executors y ScheduledExecutors), entonces HA-JDBC tiene una interfaz CronExecutorService, implementada por su CronThreadPoolExecutor. Ahora, curiosamente, tiene una dependencia con 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 solo tuve que hacer estos pequeños ajustes:

  • Eliminando el registrador de CronThreadPoolExecutor (se creó pero nunca se usó)
  • movió la constante YEAR_TO_GIVEUP_SCHEDULING_AT de CronTrigger a CronExpression

Me emocionó no haberme quedado atrapado en una maraña de dependencias. Felicidades a los autores de la clase!

Y ha estado funcionando como un campeón.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top