Ich schrieb eine Blogbeitrag zu beschreiben.
Ich zitiere den entsprechenden Text von dort:
-
Wir können einen endlichen Thread-Pool haben, der alle Aufgaben ausführt, indem er sie von einem PriorityBlockingQueue
(thread-safe heap) priorisiert auf job.nextExecutionTime()
.
-
Das bedeutet, dass das oberste Element dieses Haufens immer dasjenige sein wird, das am schnellsten ausgelöst wird.
-
Wir werden dem Standard-Threadpool-Producer-Consumer-Muster folgen.
-
Wir werden einen Thread haben, der in einer Endlosschleife läuft und neue Aufträge an den Thread-Pool weiterleitet, nachdem er sie aus der Warteschlange abgeholt hat. Nennen wir ihn QueueConsumerThread :
void goToSleep(job, jobQueue){
jobQueue.push(job);
sleep(job.nextExecutionTime() - getCurrentTime());
}
void executeJob(job, jobQueue){
threadpool.submit(job); // async call
if (job.isRecurring()) {
job = job.copy().setNextExecutionTime(getCurrentTime() + job.getRecurringInterval());
jobQueue.add(job);
}
}
@Override
void run(){
while(true)
{
job = jobQueue.pop()
if(job.nextExecutionTime() > getCurrentTime()){
// Nothing to do
goToSleep(job, jobQueue)
}
else{
executeJob(job, jobQueue)
}
}
}
-
Es wird einen weiteren Thread geben, der die crontab-Datei auf neue Aufträge überwacht und diese in die Warteschlange stellt.
-
Nennen wir es QueueProducerThread :
@Override
void run()
{
while(true)
{
newJob = getNewJobFromCrontabFile() // blocking call
jobQueue.push(newJob)
}
}
-
Allerdings gibt es dabei ein Problem:
- Stellen Sie sich vor, dass Thread1 schläft und nach einer Stunde wieder aufwacht.
- In der Zwischenzeit trifft eine neue Aufgabe ein, die jede Minute ausgeführt werden soll.
- Diese neue Aufgabe wird erst eine Stunde später ausgeführt werden können.
-
Um dieses Problem zu lösen, kann der ProducerThread den ConsumerThread zwangsweise aus dem Ruhezustand aufwecken, wenn die neue Aufgabe früher laufen muss als die vorderste Aufgabe in der Warteschlange:
@Override
void run()
{
while(true)
{
newJob = getNewJobFromCrontabFile() // blocking call
jobQueue.push(newJob)
if(newJob == jobQueue.peek())
{
// The new job is the one that will be scheduled next.
// So wakeup consumer thread so that it does not oversleep.
consumerThread.interrupt()
}
}
}
Beachten Sie, dass dies möglicherweise nicht die interne Implementierung von cron ist. Dies ist jedoch die optimalste Lösung, die ich mir vorstellen kann. Sie erfordert kein Polling und alle Threads schlafen, bis sie Arbeit verrichten müssen.