Ich entschuldige mich für die Länge dieses Problems, aber ich hielt es für wichtig, genügend Details einzubeziehen, da ich nach einem geeigneten Ansatz für mein Problem suche, anstatt nach einem einfachen Code-Vorschlag!
Ich arbeite an einem Projekt, bei dem Aufgaben in einem relativen Wiederholungsintervall
Diese Intervalle beziehen sich auf eine interne Zeit, die als Ganzzahl dargestellt wird, die bei der Ausführung des Programms inkrementiert wird ( also nicht gleich der tatsächlichen Zeit ). Jedes Mal, wenn dies geschieht, wird der Zeitplan abgefragt, um nach Aufgaben zu suchen, die zu diesem Zeitpunkt ausgeführt werden sollen.
Wenn eine Aufgabe ausgeführt wird, sollte sie erneut geplant werden, um an einer Position relativ zu der aktuellen Zeit erneut ausgeführt zu werden (z. B. in 5 Zeitschritten). Diese relative Position wird einfach als Integer-Eigenschaft des Task-Objekts gespeichert.
Ich habe Schwierigkeiten, darüber zu entscheiden, wie ich das strukturieren soll - zum Teil, weil es sich um eine etwas schwierige Suche nach Begriffen handelt.
Wie es aussieht, denke ich, dass jedes Mal, wenn der Timer inkrementiert wird, muss:
Es gibt ein paar Annahmen, die die möglichen Lösungen einschränken können, die ich verwenden kann:
Die wichtigsten Fragen, die ich habe, sind:
Wie könnte ich diesen Zeitplan so gestalten, dass er effizient funktioniert? Welche Datentypen / Sammlungen können nützlich sein?
Gibt es eine andere Struktur / Vorgehensweise, die ich in Betracht ziehen sollte?
Ist es falsch, Terminierungs-Frameworks (z. B. Quartz) zu verwerfen, die eher in der "echten" Zeitdomäne als in der "nicht realen" Zeitdomäne funktionieren?
Vielen Dank für jede mögliche Hilfe. Bitte zögern Sie nicht für weitere Informationen zu kommentieren, falls erforderlich, werde ich wo immer nötig bearbeiten!
Nun, Quartz ist ziemlich mächtige Werkzeuge, aber es hat begrenzte Konfigurationsmöglichkeiten, wenn Sie also bestimmte Funktionen benötigen, sollten Sie wahrscheinlich Ihre eigene Lösung schreiben.
Es ist jedoch eine gute Idee, den Quartz Quellcode und die Datenstrukturen zu studieren, da sie erfolgreich viele Probleme gelöst haben, die Sie z. Synchronisation zwischen Prozessen auf Datenbankebene, Ausführung von verzögerten Aufgaben usw.
Ich habe einmal meinen eigenen Scheduler geschrieben, der an Aufgaben angepasst wurde, bei denen Quartz wahrscheinlich nicht einfach anzupassen wäre, aber sobald ich Quarz gelernt habe, habe ich verstanden, wie viel ich in meinen Lösungen verbessern konnte wurde in Quarz gemacht.
Eine kreisförmige verkettete Liste könnte die Datenstruktur sein, nach der Sie suchen. Anstatt Felder in jedem Aufgabenelement zu dekrementieren, erhöhen Sie einfach den Index des 'aktuellen' Feldes in der kreisförmigen Aufgabenliste. Eine Pseudocode-Struktur könnte etwa so aussehen:
%Vor%Wenn Sie eine neue Aufgabe planen, fügen Sie sie einfach an der Position N vor dem aktuellen 'Tick'
hinzuHier sind ein paar Gedanken:
Halte alles einfach. Wenn Sie keine Millionen von Aufgaben haben, brauchen Sie keine optimierte Datenstruktur (außer Stolz oder der Drang nach voreiliger Optimierung).
Vermeiden Sie relative Zeiten. Verwenden Sie ein absolutes internes Häkchen. Wenn Sie eine Aufgabe hinzufügen, legen Sie die Option "Nächstes Mal ausführen" auf den aktuellen Tick-Wert fest. Fügen Sie es der Liste hinzu, sortieren Sie die Liste nach der Zeit.
Wenn Sie nach Aufgaben suchen, beginnen Sie am Anfang der Liste und wählen Sie alles aus, was ein Zeit & lt; = aktuelles Häkchen hat, führen Sie die Aufgabe aus.
Sammeln Sie alle Aufgaben in einer anderen Liste. Nachdem alle ausgeführt wurden, berechnen Sie das "run next time" basierend auf dem aktuellen Tick und dem Inkrement (damit Sie keine Tasks erhalten, die eine Schleife bilden), fügen Sie alle zur Liste hinzu und sortieren Sie.
Sehen Sie sich an, wie DelayQueue
eine PriorityQueue
verwendet, um eine solche geordnete Liste von Ereignissen zu verwalten. DelayQueue
arbeitet mit Echtzeit und kann daher die in Condition
und LockSupport
verfügbaren zeitgesteuerten Wartemethoden verwenden. Sie könnten etwas wie ein SyntheticDelayQueue
implementieren, das sich wie DelayQueue
verhält, aber Ihren eigenen synthetischen Zeitdienst verwendet. Sie müssten natürlich die zeitgesteuerten Warte- / Signalisierungsmechanismen ersetzen, die kostenlos mit dem jdk geliefert werden, und dies ist möglicherweise nicht einfach zu tun.
Wenn ich es tun müsste, würde ich eine einfache Warteschlange (Linked-List-Variante) erstellen. Diese Warteschlange würde eine dynamische Datenstruktur (beispielsweise eine einfache Liste) enthalten, die alle Aufgaben enthält, die erledigt werden müssen. Bei jedem Zeitintervall (oder Zeitschritt) liest der Prozess den ersten Knoten der Warteschlange und führt die Anweisungen aus, die er in der Liste dieses Knotens findet. Am Ende jeder Ausführung würde es die Neuterminierung berechnen und die neue Ausführung zu einem anderen Knoten in der Warteschlange hinzufügen oder Knoten bis zu dieser Position erstellen, bevor die Anweisung in diesem Knoten gespeichert wird. Der erste Knoten wird dann entfernt und der zweite Knoten (jetzt der erste) wird beim nächsten Zeitschritt ausgeführt. Dieses System würde auch nicht erfordern, dass ganze Zahlen verfolgt werden und alle benötigten Datenstrukturen in der Java-Sprache gefunden werden. Dies sollte Ihr Problem lösen.
Verwenden Sie einen ScheduledExecutorService . Es hat alles, was Sie brauchen, direkt eingebaut. So einfach ist es zu verwenden:
%Vor%Tags und Links algorithm java design scheduling