2009-03-05 15 views
7

Mein Programm hat eine Komponente - den Scheduler -, die es anderen Komponenten ermöglicht, Punkte in der Zeit zu registrieren, zu denen sie zurückgerufen werden möchten. Dies sollte ähnlich wie der Unix-Cron-Dienst funktionieren, d. e. Sie teilen dem Scheduler mit, dass er mich um zehn Minuten nach jeder vollen Stunde benachrichtigen soll.Java-Bibliotheksklasse für die geplante Ausführung von "Callbacks"?

Ich weiß, es gibt keine echten Callbacks in Java.

Hier ist mein Ansatz, gibt es eine Bibliothek, die das Zeug schon tut? Fühlen Sie sich frei, auch Verbesserungen vorzuschlagen.

Register Anruf Scheduler passiert:

  • eine Zeitangabe enthält, Stunde, Minute, Sekunde, Jahr Monat, dom, dow, wobei jedes Element nicht spezifiziert sein kann, was bedeutet, „führen Sie es jede Stunde/Minute usw. " (Genau wie crontabs)
  • ein Objekt, das Daten enthält, die dem aufrufenden Objekt mitteilen, was zu tun ist, wenn es vom Scheduler gemeldet wird. Der Scheduler verarbeitet diese Daten nicht, sondern speichert sie und gibt sie bei Benachrichtigung zurück.
  • ein Verweis auf das aufrufende Objekt

Nach dem Start oder nach einer neuen Registrierungsanforderung, startet der Scheduler mit einem Kalender-Objekt der aktuellen Systemzeit und prüft, ob es irgendwelche Einträge in der Datenbank vorhanden ist, die dieses Spiel Zeitpunkt. Wenn dies der Fall ist, werden sie ausgeführt und der Prozess beginnt von vorne. Ist dies nicht der Fall, wird die Zeit im Calendar-Objekt um eine Sekunde erhöht und die Entries werden erneut überprüft. Dies wird wiederholt, bis mindestens ein Eintrag vorhanden ist. (Diskrete Ereignissimulation)

Der Scheduler wird sich dann daran erinnern, dass Zeitstempel, Schlaf und Wachen jede Sekunde, um zu prüfen, ob es schon da ist. Wenn es aufwacht und die Zeit bereits verstrichen ist, beginnt es wieder, wenn die Zeit gekommen ist und die Aufträge ausgeführt wurden.


bearbeiten: Vielen Dank für mich zu Quartz zeigt. Ich suche jedoch etwas viel kleineres.

Antwort

4

Wenn sich Ihre Bedürfnisse einfach sind, betrachten java.util.Timer mit:

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(); 
    } 
    } 

} 

Wie noted gewesen ist, die ExecutorService von java.util.concurrent bietet eine reichere API, wenn Sie es brauchen.

4

Quartz ist das große und offensichtliche Kraftpaket in diesem Bereich, aber es gibt einige Alternativen zu entdecken.

Cron4j ist eine anständige genug Bibliothek, die ein wenig leichter als Quarz ist. Es bietet eine gute Dokumentation und wird tun, was Sie wollen.

Wahrscheinlich interessanter ist, wenn Sie eine Bibliothek verwenden möchten, die mit Java Concurrency Bibliotheken besser passt (insbesondere Testamentsvollstrecker und ScheduledExecutors) dann HA-JDBC hat eine CronExecutorService Schnittstelle, durch seine CronThreadPoolExecutor umgesetzt. Interessanterweise hat es eine Abhängigkeit von Quartz (um die CronExpression-Klasse bereitzustellen), aber ich finde, dass die beiden zusammen besser funktionieren als nur Quartz. Wenn Sie keine großen Abhängigkeiten wünschen, ist es einfach, die Handvoll Klassen aus Quartz und HA-JDBC zu extrahieren, die dies ermöglichen.

Da Sie etwas viel kleiner wollen (bemerkte nur Ihre Bearbeitung), greifen Sie nach CronExpression von Quartz und den zwei oben erwähnten HA-JDBC-Klassen. Das wird es tun.

5

Wenn Ihre Objekte genau die einzelnen Zeitpunkte kennen, die sie ausführen möchten, können Sie eine java.util.concurrent.ScheduledExecutorService verwenden. Dann werden sie einfach Aufruf:

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

würden Sie brauchen nur Quartz zu verwenden, wenn Sie den Planer selbst wollen Funktionalität behandeln wie „execute alle 5 Sekunden“, oder wenn Sie wollen komplexes Verhalten um vermisste Hinrichtung oder die Persistenz des Ausführungs-Audit-Trails.

Sie können Quartz CronTrigger Klasse trivialerweise wiederverwenden, um eine "nächste Ausführungszeit" zu erhalten. Die Klasse ist vollständig eigenständig und hängt nicht davon ab, dass sie innerhalb des Quartz "Kontexts" aufgerufen wird. Sobald Sie die nächste Ausführungszeit als Date oder long haben, können Sie einfach die Java verwenden ScheduledExecutorService wie oben

0

Ich kann nicht glauben, dass java.util.Timer als die Antwort gewählt wurde. Quarz ist wirklich eine viel bessere Wahl.

Ein großer Vorteil von Quarz gegenüber java.util.Timer ist, dass mit Quarz die Jobs in der db gespeichert werden können. Als Ergebnis kann ein jvm planen und ein anderer ausführen. Auch (offensichtlich) überlebt die Anfrage über jvm Neustarts.

+0

Ja, aber ich brauchte etwas wirklich einfaches, ohne zusätzliche Abhängigkeiten. Ich habe sowieso Beharrlichkeit in meiner App behandelt, der Scheduler benötigt es selbst nicht. Ich habe allerdings Quarz auf meiner Liste, sollte ich später mehr Leistung brauchen. –

+0

In der neuesten Version können Sie jetzt neben einer Datenbank auch Quartz-Jobs mit Terracotta zusammenfassen. –

+1

Es ist witzig, dass Quarz-Persistenz-Funktionen als großer Vorteil angepriesen werden: in vielen Fällen sind sie nur ein großer PITA. – StaxMan

0

Wahrscheinlich interessanter ist, wenn Sie eine Bibliothek verwenden möchten, die mit Java Concurrency Bibliotheken besser passt (insbesondere Testamentsvollstrecker und ScheduledExecutors) dann HA-JDBC hat eine CronExecutorService Schnittstelle, durch seine CronThreadPoolExecutor umgesetzt. Interessanterweise hat es eine Abhängigkeit von Quartz (um die CronExpression-Klasse bereitzustellen), aber ich finde, dass die beiden zusammen besser funktionieren als nur Quartz. Wenn Sie keine großen Abhängigkeiten wünschen, ist es einfach, die Handvoll Klassen aus Quartz und HA-JDBC zu extrahieren, die dies ermöglichen.

Ich wollte nur sagen, dass ich versucht habe, diese Klassen zu extrahieren, und es hat funktioniert! Ich brauchte diese drei Klassen:

  • CronExpression (Quarz)
  • CronThreadPoolExecutor (ha-jdbc)
  • DaemonThreadFactory (ha-jdbc)

Und ich hatte nur diese kleineren Verbesserungen zu tun:

  • Entfernen des Loggers von CronThreadPoolExecutor (es erstellt wurde, aber nie benutzt)
  • Verschoben die Konstante YEAR_TO_GIVEUP_SCHEDULING_AT von CronTrigger CronExpression

Ich war begeistert, dass ich nicht stecken Pull in einem Gewirr von Abhängigkeiten erhalten haben. Glückwunsch an die Klassenautoren!

Und es funktioniert wie ein Champion.

1

Ich würde dringend cron4j (bereits erwähnt) über Quarz empfehlen, es sei denn, Sie benötigen unbedingt einige der fortgeschritteneren und komplexeren Funktionen von Quarz. Cron4j konzentriert sich gut auf das, was es tun soll, hat anständige Dokumentation und ist keine Lösung für Küchenspülungen.

Verwandte Themen