2009-03-05 11 views
7

Il mio programma ha un componente - soprannominato lo Scheduler - che consente ad altri componenti di registrare punti nel tempo in cui vogliono essere richiamati. Questo dovrebbe funzionare molto come il servizio cron di Unix, i. e. dite allo Scheduler di "notificarmi alle dieci minuti dopo ogni ora piena".Classe libreria Java per gestire l'esecuzione pianificata di "callback"?

Mi rendo conto che non ci sono veri callback in Java.

Ecco il mio approccio, c'è una libreria che già fa queste cose? Sentiti libero di suggerire anche miglioramenti.

Registrati chiamata alla pianificazione passa:

  • una specifica tempo contenente ore, minuti, secondi, mese anno, dom, Dow, in cui ogni elemento può essere specificato, che significa "eseguirlo ogni ora/minuto ecc " (proprio come crontabs)
  • un oggetto contenente dati che dirà all'oggetto chiamante cosa fare quando viene notificato dallo Scheduler. Lo Scheduler non elabora questi dati, lo memorizza e lo restituisce alla notifica.
  • un riferimento all'oggetto chiamante

All'avvio, o dopo una nuova richiesta di registrazione, l'utilità di pianificazione inizia con un oggetto calendario del tempo di sistema attuale e controlla se ci sono voci nel database che corrispondono a questa punto nel tempo. Se ci sono, vengono eseguiti e il processo ricomincia. In caso contrario, l'ora nell'oggetto Calendar viene incrementata di un secondo e gli entreis vengono ricontrollati. Questo si ripete finché non c'è una voce o più che corrispondono (es). (Simulazione di eventi discreti)

L'Utilità di pianificazione ricorderà quindi la data/ora, si addormenterà e si riattiverà ogni secondo per verificare se è già presente. Se capita di svegliarsi e il tempo è già passato, ricomincia, allo stesso modo se è giunto il momento e i lavori sono stati eseguiti.


Edit: Grazie per avermi al quarzo. Sto cercando qualcosa di molto più piccolo, tuttavia.

risposta

4

Se le vostre esigenze sono semplici, considerare l'utilizzo di 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(); 
    } 
    } 

} 

Come è stato noted, il ExecutorService di java.util.concurrent offre un'API più ricca se ne hai bisogno.

4

Quartz è la grande e ovvia centrale elettrica in questo settore, ma ci sono alcune alternative da esplorare.

Cron4j è una libreria abbastanza decente, che è un po 'più leggera di Quartz. Fornisce una buona documentazione e farà ciò che vuoi.

Probabilmente più interessante è se si desidera utilizzare una libreria che si adatta meglio con le librerie di concorrenza di Java (in particolare Esecutori e ScheduledExecutors) poi HA-JDBC ha un'interfaccia CronExecutorService, implementata dalla sua CronThreadPoolExecutor. Ora, interessante, ha una dipendenza da Quartz (per fornire la classe CronExpression), ma trovo che i due insieme funzionano meglio del solo Quartz. Se non vuoi grandi dipendenze, è facile estrarre la manciata di classi da Quartz e HA-JDBC che rendono questo possibile.

Dal momento che si desidera qualcosa di molto più piccolo (appena notato la modifica), acquisire CronExpression da Quartz e le due classi HA-JDBC che ho menzionato sopra. Questo lo farà

5

Se gli oggetti conoscono esattamente i singoli punti nel tempo in cui desiderano essere eseguiti, è possibile utilizzare uno java.util.concurrent.ScheduledExecutorService. Poi semplice chiamata:

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

Faresti solo bisogno di utilizzare Quartz se si desidera che lo scheduler stesso per gestire funzionalità come "eseguire ogni 5 secondi", o se si vuole un comportamento complesso esecuzioni intorno perse o la persistenza della pista di controllo dell'esecuzione.

È possibile riutilizzare banalmente la classe CronTrigger di Quartz per ottenere un "prossimo tempo di esecuzione". La classe è completamente autonoma e non dipende dall'essere richiamata all'interno del "contesto" Quartz. Una volta che hai il tempo di esecuzione successivo come Date o long, si può semplicemente utilizzare il Java ScheduledExecutorService come sopra

0

Non posso credere che java.util.Timer sia stata votata come risposta. Il quarzo è davvero una scelta molto migliore.

Un grande vantaggio del quarzo su java.util.Timer è che con il quarzo i lavori possono essere memorizzati nel db. Di conseguenza, una jvm può programmare e un'altra può essere eseguita. Inoltre (ovviamente) la richiesta sopravvive attraverso i riavvii di jvm.

+0

Sì, ma avevo bisogno di qualcosa di veramente semplice, senza dipendenze aggiuntive. Comunque, ho mantenuto la persistenza nella mia app, lo scheduler non ne ha bisogno da solo. Ho quarzo sulla mia lista però, dovrei aver bisogno di più potenza in seguito. –

+0

Nella versione più recente, ora è possibile raggruppare i lavori Quartz con Terracotta in aggiunta a un database. –

+1

È buffo che le caratteristiche di persistenza del Quarzo siano pubblicizzate come un grande vantaggio: in molti casi/molti casi sono solo una grande PITA. – StaxMan

0

Probabilmente più interessante è se si desidera utilizzare una libreria che si adatta meglio con le librerie di concorrenza di Java (in particolare Esecutori e ScheduledExecutors) poi HA-JDBC ha un'interfaccia CronExecutorService, attuate dal suo CronThreadPoolExecutor. Ora, interessante, ha una dipendenza da Quartz (per fornire la classe CronExpression), ma trovo che i due insieme funzionano meglio del solo Quartz. Se non vuoi grandi dipendenze, è facile estrarre la manciata di classi da Quartz e HA-JDBC che rendono questo possibile.

Volevo solo dire che ho provato a estrarre queste classi e ha funzionato! Avevo bisogno di queste tre classi:

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

e ho avuto solo a fare queste modifiche minori:

  • Rimozione del logger da CronThreadPoolExecutor (è stato creato, ma mai utilizzato)
  • spostato i YEAR_TO_GIVEUP_SCHEDULING_AT costante da CronTrigger a CronExpression

ero entusiasta che non ho avuto tiro bloccato in un groviglio di dipendenze. Congratulazioni agli autori di classe!

E ha funzionato come un campione.

1

Consiglio vivamente lo cron4j (già menzionato) su Quartz, a meno che non sia assolutamente necessario disporre di alcune delle funzionalità più avanzate e complesse di Quartz. Cron4j si concentra benissimo su cosa dovrebbe fare, ha una documentazione decente e non è una soluzione per il lavandino della cucina.