Eine Timing -Aufgabe ist eine Funktion der Angabe eines zukünftigen Zeitbereichs, um bestimmte Aufgaben auszuführen. In aktuellen Webanwendungen verfügen die meisten Anwendungen über Aufgabenplanungsfunktionen. Sie haben ihre eigene Syntax und Lösungen für verschiedene Stimmen und Betriebssysteme. Das Windows -Betriebssystem ruft die Aufgabenplanung auf, und die Cron -Dienste in Linux bieten diese Funktion. Diese Funktion ist häufig an unserem Geschäftsentwicklungssystem beteiligt. In diesem Chat wird die Java -Sprache verwendet, um die Verwendung häufig verwendeter Zeitaufgaben in der täglichen Entwicklungsarbeit zu erledigen, in der Hoffnung, allen Arbeiten und Studien zu helfen.
1. zeitgesteuerte Aufgabenszenarien
(1) Workflow für den Bearbeitung der Verarbeitung
Als neue Prepaid -Bestellung wird es initialisiert und platziert. Wenn die Bestellung nicht innerhalb der angegebenen Zeit bezahlt wird, wird berücksichtigt, dass die Timeout -Bestellung geschlossen wird. Es wird im E-Commerce-System häufig verwendet. Benutzer kaufen Waren und erstellen Bestellungen, leisten jedoch keine Zahlungen. Wenn die Bestellung nicht innerhalb von 30 Minuten bezahlt wird, wird die Bestellung geschlossen (und die Anzahl der Personen, die dieses Szenario treffen), und es ist unmöglich, manuelle Eingriffe zu verwenden.
(2) Systemwartung
In der Versandarbeit wird das System -Ausnahmebodus erhalten und einige wichtige Punktdaten in der Datenbank gespeichert. Es wird jeden Wochentag um 23:30 Uhr (außer Feiertagen und Wochentagen) in die Datenbank abgeladen, eine XML -Datei generiert und an die E -Mail -Adresse eines bestimmten Mitarbeiters sendet.
(3) Erinnerungsdienste innerhalb der Anwendung anbieten.
Das System erinnert den angemeldeten Benutzer regelmäßig daran, zu einem bestimmten Zeitpunkt verwandte Arbeiten auszuführen.
(4) zeitgesteuerte Versöhnungsaufgaben
Das Unternehmen und die Drei-Partner-Unternehmen (Betreiber, Banken usw.) werden jeden Tag am selben Tag nach Mitternacht eine Abstimmung des Geschäfts durchführen, die Datenergebnisdaten der Versöhnung an die E-Mail-Adresse der zuständigen Person senden und die Fehlpaarungsdaten während der Arbeitszeit des nächsten Tages verarbeiten.
(5) Datenstatistik
Es gibt viele Datensätze, und das Lesen und Abfragen von Echtzeit aus der Datenbank generiert eine bestimmte Zeit, die für Kundenerfahrung und Leistungsanforderungen gilt. Daher werden die Daten jede Woche (Tage, Stunden) zusammengefasst, damit die Daten bei der Anzeige der Daten schnell vorgestellt werden können.
Es gibt viele Szenarien, in denen Timing -Aufgaben verwendet werden ... Es scheint, dass die Timing -Aufgaben in unserer täglichen Entwicklung wirklich weit verbreitet sind ...
2. Erläuterung des Technologie -Timers für Mainstream -Timing -Aufgaben
Ich glaube, jeder ist bereits sehr vertraut mit Java.util.timer. Es ist der einfachste Weg, die Aufgabenplanung zu implementieren. Hier ist ein spezifisches Beispiel:
Paket com.ibm.scheduler; import Java.util.timer; import Java.util.timertask; public class timertest erweitert timerTask {private String jobname = ""; public timertest (String JobName) {Super (); this.jobname = JobName; } @Override public void run () {System.out.println ("execute" + JobName); } public static void main (String [] args) {Timer Timer = new Timer (); lange Verzögerung1 = 1 * 1000; lange Period 1 = 1000; // nach 1 Sekunde in ab sofort ein Job1 Timer.Schedule (neuer Timertest ("Job1"), Delay1, Period1) ausführen; Long Delay2 = 2 * 1000; Langperiode 2 = 2000; // Führen Sie nach 2 Sekunden in jetzt Job2 Timer.Schedule (neuer Timertest ("Job2"), Delay2, Period2) aus; }} /**
Ausgangsergebnis:
HiBe1 ausführen1
HiBe1 ausführen1
HiBe2 ausführen2
HiBe1 ausführen1
HiBe1 ausführen1
HiBe2 ausführen2
*/
Die Kernklassen, die Timer verwenden, um die Aufgabenplanung zu implementieren, sind Timer und Timertask. Der Timer ist für die Festlegung der Start- und Intervallausführungszeit von Timertask verantwortlich. Der Benutzer muss nur eine Vererbungsklasse von Timertask erstellen, eine eigene Run -Methode implementieren und dann zur Ausführung in den Timer werfen. Der Designkern von Timer ist eine Taskliste und ein TaskThread. Timer wirft die empfangenen Aufgaben in seine Taskliste aus, die die Taskliste entsprechend der anfänglichen Ausführungszeit der Aufgabe sortiert. TimerThread wird beim Erstellen von Timer zu einem Daemon -Thread. Dieser Thread befragt alle Aufgaben, findet eine kürzlich ausgeführte Aufgabe und schläft dann. Wenn die Startzeit der zuletzt ausgeführten TimerThread geweckt und die Aufgabe ausgeführt wird. Danach aktualisiert TimerThread die neueste Aufgabe, die ausgeführt wird und weiterhin Winterschlaf.
Der Vorteil des Timers besteht darin, dass es einfach und einfach zu bedienen ist, aber da alle Aufgaben durch denselben Thread geplant sind, werden alle Aufgaben seriell ausgeführt, und nur eine Aufgabe kann gleichzeitig ausgeführt werden. Die Verzögerung oder Ausnahme der vorherigen Aufgabe wirkt sich auf die nachfolgenden Aufgaben aus (dieser Punkt muss beachtet werden).
Geplantexezier
In Anbetracht der oben genannten Mängel von Timer hat Java 5 pledulEdexecutor basierend auf Thread Pool Design gestartet. Die Designidee ist, dass jede geplante Aufgabe von einem Thread im Thread -Pool ausgeführt wird, sodass die Aufgaben gleichzeitig ausgeführt werden und nicht voneinander gestört werden. Es ist zu beachten, dass Schedudexecutor nur einen Thread startet, wenn die Ausführungszeit der Aufgabe erfolgt, und der Schedudexecutor die Aufgabe für den Rest der Zeit befragt.
Paket com.ibm.scheduler; import Java.util.concurrent.executors; import Java.util.concurrent public plantedexecUTORTEST (String JobName) {Super (); this.jobname = JobName; } @Override public void run () {System.out.println ("execute" + JobName); } public static void main (String [] args) {plantedexecutorService Service = Executors.NewScheduledThreadpool (10); lange initialdelay1 = 1; lange Period 1 = 1; // nach 1 Sekunde in der nun an, yiB1 service.Scheduleatfixedrate (neue afulEdexecutportest ("Job1"), Initialdelay1, Period1, TimeUnit.Seconds) ausführen; lange initialdelay2 = 1; lange Verzögerung2 = 1; // nach 2 Sekunden in der NOUSTIGE HOB2 service.SchedulewithFixedDelay (neue planteDexecutportest ("Job2"), InitialdElay2, Delay2, TimeUnit.seconds) ausführen; }}/** Ausgabeergebnis: Führen Sie Job1Execute -job1Execute2Execute -Job1Execute -Job1Execute Job2*/aus
Der obige Code zeigt zwei am häufigsten verwendete Zeitplanungsmethoden: ScheduleatFixedrate und SchedulewithFixedDelay in enderedelta. ScheduleatFixedrate Jede Ausführungszeit ist ein Zeitintervall, das von Beginn der vorherigen Aufgabe zurückdrückt, dh jede Ausführungszeit ist: initialdelay, initieldelay+Periode, initieldelay+2*Periode,… SchedulewithfixedDelay Jede Ausführungszeit ist ein Zeitintervall, der von der vorherigen Aufgabe zurückgedrängt wird. InitialdElay+ExecutTime+Delay, InitialdElay+2*ExecutETime+2*Verzögerung. Es ist zu sehen, dass ScheduleatFixedRate auf festen Zeitintervallen für die Aufgabenplanung basiert, und SchedulewithFixedDelay hängt von der Länge der einzelnen Aufgabenausführungszeiten ab und basiert auf nicht festgelegten Zeitintervallen für die Aufgabenplanung.
Verwenden
Sowohl der Timer als auch der Scheduledexecutor können nur die Aufgabenplanung basierend auf dem Startzeit- und Wiederholungsintervall bereitstellen und sind nicht kompetent für komplexere Planungsanforderungen. Legen Sie beispielsweise die Aufgabe fest, jeden Dienstag um 16:38:10 Uhr ausgeführt zu werden. Diese Funktion kann nicht direkt mit dem Timer oder teplaneDexecutor implementiert werden, aber wir können sie indirekt mit Hilfe des Kalenders implementieren.
Paket com.ibm.scheduler; import java.util.calendar; import Java.util.date; import Java.util.timertask; Import Java.util.Concurrent.executors; TimerTask {private String jobname = ""; public plantedexceutest2 (String JobName) {Super (); this.jobname = JobName; } @Override public void run () {System.out.println ("Date ="+new Date ()+", execute"+JobName); } /** * Berechnen Sie die neueste Zeit, die mit dem aktuellen Zeitpunkt startet und die Bedingungen Tag der Woche, Hourofday, * minuteofhour, zweitofminit * @return * /öffentlicher Kalender GETEARLIESTDATE (CALENDAR CURROLDATE, INT DAYOFWEEK, INTHAIT, INT MINIGING MINIGING, DAYOFME, DAYOFME, DAYOFMET) {/ // // calculat, tagsofHour, tagsüber, in der zweiten Stelle) {/ // // calculation the woiinofday, tagsof -zweites, int. Hour_of_day, Minute, Second usw. int currentweePyear = currentDate.get (Calendar.week_of_year); int currentdayofweek = currentDate.get (Calendar.day_of_week); int currentHour = currentDate.get (calendar.hour_of_day); int currentMinute = currentDate.get (calendar.minute); int currentSecond = currentDate.get (calendar.second); // Wenn der Tag der Week in der Eingabebedingung geringer ist als der Tag der Woche des aktuellen Datums, muss Week_of_year um eine Woche verschoben werden, boolean weelater = false; if (tayofweek <currentdayofweek) {weewlater = true; } else if (tayofweek == currentdayofweek) {// Wenn die Eingabebedingung gleich dem Tag der Woche des aktuellen Datums ist, ist wenn // Hourofday in der Eingabebedingung weniger als // currentHour des aktuellen Datums, week_of_year, um eine Woche zu verschieben, wenn (HourOfday <currentdayHour) {Weelater = True; } else if (HourOfday == CurrentHour) {// Wenn die Eingabebedingung gleich dem Tag der Woche ist, stündlich des aktuellen Datums, // Wenn die MinuteofHour in der Eingabebedingung weniger als // currentMinute des aktuellen Datums ist, muss week_of_year um eine Woche nachgeponiert werden, wenn (wöchentliche minuteOfhour <currentMinute) {wöchentlich = echt; } else if (minuteOfHour == currentsecond) {// Wenn die Eingabebedingung gleich dem Tag der Woche ist, stündlich, // MinuteofHour, wenn // zweitofminit in der Eingabebedingung weniger als die Currentsecond des aktuellen Datums des aktuellen Datums ist, muss wöchentlich eine Woche einwöchentlich nach einer Woche nach einer Woche nachverfolgt werden. }}}}} if (wöchentliche) {// setze week_of_year im aktuellen Datum, um eine Woche CurrentDate.set zu verschieben (Calendar.week_of_year, CurrentweePyear + 1); } // Setzen Sie DAY_OF_WEEP, HOST_OF_DAY, Minute, Sekunde im aktuellen Datum als Werte in der Eingabebedingung. currentDate.set (Calendar.day_of_week, Dayofweek); currentDate.set (Calendar.hour_of_day, Hourofday); CurrentDate.set (Calendar.minute, MinuteOfHour); CurrentDate.set (Calendar.second, SecondofMinite); Return CurrentDate zurückgeben; } public static void main (String [] args) löst eine Ausnahme aus {planedexceutest2 test = new PlaneDexceutest2 ("Job1"); // Erhalten Sie den aktuellen Zeitkalender currentDate = calendar.getInstance (); long CurrentDatelong = currentDate.getTime (). GetTime (); System.out.println ("Current Datum =" + currentDate.getTime (). ToString ()); // Berechnen Sie die letzte Ausführungszeit, die den Zustandskalender früher erfüllt. lange früherDatelong = EarlyDate.getTime (). GetTime (); System.out.println ("frühestes date =" + früherdate.getTime (). ToString ()); // Berechnen Sie das Zeitintervall von der aktuellen Zeit bis zur letzten Ausführungszeit Long Delay = frühere Datelong - CurrentDatelong; // Berechnen Sie die Ausführungszeit dauert eine Woche lang Periode Länge = 7 * 24 * 60 * 60 * 1000; EnderedexecutorService Service = Executors.NewScheduledThreadpool (10); // Abverzögern Sie Millisekunden, führen Sie Job1 service.Scheduleatfixedrate (Test, Verzögerung, Zeitraum, Zeitunit.Milliseconds) aus; }}/** Ausgabergebnis: aktuelles Datum = Mi Feb 02 17:32:01 CST 2011ErLEST DATUM = Di 8. Februar 16:38:10 CST 2011Date = Di 8. Februar 16:38:10 CST 2011, Execute Job1Date = Di 15. Februar 16:38:10 CST 2011, Execute Job1*///
Der obige Code implementiert die Funktion der Planungsaufgaben jeden Dienstag um 16:38:10 Uhr. Der Kern besteht darin, die absolute Zeit von 16:38:10 am letzten Dienstag basierend auf der aktuellen Zeit zu berechnen und dann die Zeitdifferenz von der aktuellen Zeit als Parameter für die Aufrufe der ender -Ausführungsfunktion zu berechnen. Um die neueste Zeit zu berechnen, wird die Funktion von java.util.calendar verwendet. Zunächst müssen wir einige Designideen des Kalenders erklären. Der Kalender verfügt über die folgenden Kombinationen, die ein Datum eindeutig identifizieren:
Zitat
Jahr + Monat + Day_of_month
Jahr + Monat + Woche_OF_Month + Day_of_week
Jahr + Monat + Day_of_week_in_month + Day_of_week
Jahr + Day_of_year
Jahr + Day_of_week + week_of_year
Die obigen Kombinationen werden mit HourOfday + Minute + Second kombiniert, um eine komplette Zeit zu sein.
Die obige Demo verwendet die letzte Kombinationsmethode. Die Eingabe ist DAY_OF_WEEK, HOST_OF_DAY, Minute, Second und das aktuelle Datum, und die Ausgabe ist ein zukünftiges Datum, an dem Day_of_week, Hour_of_day, Minute, Second erfüllt und dem aktuellen Datum am nächsten kommt. Das Berechnungsprinzip besteht darin, den Vergleich vom Eingangstag_of_Week zu beginnen. Wenn es weniger als der Tag des aktuellen Datums ist, müssen Sie die Woche_OF_YEAR weiter erhöhen, dh die Woche_OF_YEAR zum aktuellen Datum und überschreiben Sie den alten Wert. Wenn es dem aktuellen Tag entspricht, vergleichen Sie weiterhin Hour_of_day. Wenn es größer ist als die aktuelle Day_of_week, rufen Sie direkt die Funktion von Calendar.set (Feld, Wert) von java.util.calenda an, um den Day_of_Week, Hour_of_day, Minute, Second zum Eingabewert usw. zuzuweisen, bis der Vergleich auf zweiter Stelle erreicht ist. Wir können verschiedene Kombinationen basierend auf den Eingabeanforderungen auswählen, um die neueste Ausführungszeit zu berechnen.
Es ist ziemlich umständlich, die Aufgabenplanung mithilfe der obigen Methode zu implementieren. Wir hoffen, ein umfassenderes Aufgabenplanungstool zu benötigen, um diese komplexen Planungsprobleme zu lösen. Glücklicherweise hat der Open -Source -Toolkit -Quarz in dieser Hinsicht großartige Fähigkeiten gezeigt.
Quarz
OpenSymphony Open Source Organization ist ein weiteres Open -Source -Projekt im Bereich der Jobplanung, das mit J2EE- und J2SE -Anwendungen kombiniert oder allein verwendet werden kann. Quarz kann verwendet werden, um einfache oder komplexe Programme zu erstellen, die zehn, Hunderte oder sogar Zehntausende von Arbeitsplätzen betreiben.
Schauen wir uns ein Beispiel an:
paket com.test.quartz; import static org.quartz.datebuilder.newdate; import static org.quartz.jobbuilder.newjob; statische org.quartz.Simplesschettenbuilder.-Simples; org.quartz.jobdetail; import org.quartz.scheduler; import org.quartz.trigger; Scheduler = StdSchedulerFactory.getDefaultScheduler (); // Definieren Sie einen Trigger Trigger Trigger = newtrigger (). Mit Identität ("Trigger1", "Group1") // Name/Gruppe definieren. ist immer noch nicht gestoppt.build (); // Definieren Sie einen Jobdetail JobDetail Job = newjob (helloquartz.class) // Die Jobklasse als HelloQuartz -Klasse definieren, was die echte Ausführungslogik ist. // Zu diesem Scheduler.Schedulejob (Job, Trigger) hinzufügen; // start plantuler.start (); // geschlossener Thread.Sleep (10000); Scheduler.Shutdown (True); } catch (Ausnahme e) {e.printstacktrace (); }}} paket com.test.quartz; import java.util.date; import org.quartz.disallowConcurrentexecution; import org.quartz.job; execute (JobExecutionContext Context) löst JobExecutionException {JobDetail detail = context.getJobDetail () aus; String name = detail.getjobDatamap (). GetString ("name"); System.out.println ("Hallo zu" + name + "bei" + New Date ()); }}In den obigen Beispielen: Die 3 wichtigsten Grundelemente von Quarz:
• Scheduler: Scheduler. Die gesamte Planung wird dadurch gesteuert.
• Auslöser: Definiert die Auslöserbedingung. Im Beispiel ist sein Typ einfach, der alle 1 Sekunde ausgeführt wird (was SimpleTigger ist, wird im Folgenden ausführlich beschrieben).
• Jobdetail & Job: JobDetail definiert Aufgabendaten, und die tatsächliche Ausführungslogik steht im Job im Beispiel Helloquartz. Warum wird es als Jobdetail + Job konzipiert und nicht direkt Job verwenden? Dies liegt daran, dass es möglich ist, Aufgaben gleichzeitig auszuführen. Wenn Scheduler Jobs direkt verwendet, besteht ein Problem des gleichzeitigen Zugriffs auf dieselbe Jobinstanz. In der JobDetail & Job -Methode wird jedes Mal, wenn der Sheduler ausgeführt wird, eine neue Jobinstanz basierend auf dem JobDetail erstellt, sodass das Problem des gleichzeitigen Zugangs vermieden werden kann.
Quarz -API
Der API -Stil von Quartz erfolgt nach 2.x und nimmt den DSL -Stil an (bedeutet normalerweise einen fließenden Schnittstellenstil), der im Beispiel der Newtrigger () -Teil ist. Es wird durch den Bauherr implementiert, was Folgendes ist. (Die meisten der folgenden Codes beziehen sich auf diese Bauherren)
// berufsbezogene Builderport statische org.quartz.jobbuilder. org.quartz.dailytimeIntervalsschonteneBuilder. Vergleichen Sie: Jobdetail JobDetail = New JobDetailImpl ("Jobdetail1", "Group1", Helloquartz.Class); JobDetail.getJobdatamap (). Put ("Name", "Quartz"); Date ()); Trigger.SetRepeatInterval (1); Trigger.SetRepeatCount (-1);Über Namen und Gruppe
Jobdetail und Trigger haben Namen und Gruppe.
Name ist ihre eindeutige Kennung in diesem Schatten. Wenn wir eine Jobdetail -Definition aktualisieren möchten, müssen wir nur eine Jobdetail -Instanz mit demselben Namen festlegen.
Group ist eine Organisationseinheit, und Sheduler wird einige APIs für die gesamte Gruppe von Operationen wie Scheduler.ResumeJobs () bereitstellen.
Auslösen
Bevor Sie anfangen, jeden Auslöser im Detail zu erklären, müssen Sie einige Gemeinsamkeiten des Triggers verstehen.
StartTime & Endime
Das von Start Time und Endtime angegebene Zeitintervall wird ausgelöst. Außerhalb dieses Intervalls wird der Trigger nicht ausgelöst. Alle Auslöser enthalten diese beiden Eigenschaften.
Priorität
Wenn der Scheduler beschäftigt ist, können gleichzeitig mehrere Auslöser ausgelöst werden, die Ressourcen sind jedoch nicht ausreichend (z. B. unzureichender Fadenpool). Zu diesem Zeitpunkt ist ein besserer Weg als ein Scherenstoff, Priorität zu setzen. Führen Sie zuerst die Priorität aus. Es ist zu beachten, dass die Priorität nur zwischen Triggern funktioniert, die gleichzeitig ausgeführt werden, wenn ein Auslöser 9:00 und der andere Auslöser 9:30 ist. Egal wie hoch die nächste Priorität ist, der vorherige wird zuerst ausgeführt. Der Standardwert der Priorität beträgt 5 und der Standardwert wird verwendet, wenn er negativ ist. Der Maximalwert scheint nicht angegeben zu sein, es wird jedoch empfohlen, den Java-Standard zu folgen und 1-10 zu verwenden. Andernfalls, wenn Sie wissen, ob ein größerer Wert darauf ist, wenn Sie sehen [Priorität ist 10].
Fehlzündung (Miss Trigger) Strategie
Wenn ähnliche Scheduler -Ressourcen unzureichend sind oder wenn die Maschine abstürzt und neu startet, ist es möglich, dass einige Auslöser zum Zeitpunkt nicht ausgelöst werden, wenn sie ausgelöst werden sollten, das heißt, Miss Fire. Zu diesem Zeitpunkt benötigt Trigger eine Strategie, um diese Situation zu bewältigen. Die optionalen Strategien für jeden Auslöser variieren. Hier sind zwei Punkte, auf die Sie sich beachten können:
Fehlfeuerauslöser hat einen Schwellenwert, der im Jobstore konfiguriert ist. Mehr als Ramjobstore ist org.quartz.jobstore.misfirethreshold. Fehlzündung wird nur als diesen Schwellenwert überschritten. Weniger als dieser Schwellenwert wird Quarz abgerissen. Alle Fehlzündungsstrategien beantworten tatsächlich zwei Fragen:
• Muss das Fehlzündung neu ausgelöst werden?
• Wenn ein Fehlfeuer auftritt, möchten Sie die vorhandene Zeitplanungszeit anpassen?
Beispielsweise umfasst die Fehlzündungsstrategie von Simpligger::
• Misfire_instruction_ignore_misfire_policy Dies bedeutet nicht, den verpassten Auslöser zu ignorieren, sondern die Fehlzündungspolitik zu ignorieren. Es wird alle Fehlzündungsaufgaben abrufen, wenn die Ressource angemessen ist und die vorhandene Zeitplanungszeit nicht beeinträchtigt. Zum Beispiel wird Simpligger alle 15 Sekunden ausgeführt, und es hat 5 Minuten in der Mitte und vermisst 20 fehlt. Nach 5 Minuten wird unter der Annahme, dass die Ressourcen ausreichen und die Aufgabe die Parallelität ermöglicht, gleichzeitig ausgelöst. Diese Eigenschaft gilt für alle Auslöser.
• Misfire_instruction_fire_now ignorieren Aufgaben, die fehlfeuer waren und die Zeitpläne sofort ausführen. Dies gilt normalerweise nur für Aufgaben, die nur einmal ausgeführt werden.
• MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT Setzen Sie die Startzeit auf die aktuelle Zeit und planen Sie die Aufgabe sofort, einschließlich Fehlfeuer.
• MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMING_REPEAT_COUNT Ähnlich wie bei MisfireinSructionResplanenowwithExistingRepeat_Count, der Unterschied besteht darin, dass Aufgaben, die bereits falsch vorgebracht wurden, ignoriert werden.
• MISFIRE_INSTRUCTION_RESEDULE_NEXT_WITH_EXISTING_COUNT zum nächsten geplanten Zeitpunkt starten Sie die Versandaufgabe, einschließlich Fehlfeuer.
• MISFIRE_INSTRUCTION_RESCHANDULE_NEXT_WITH_REMING_COUNT Ähnlich wie bei MisfireinSructionResplanenextwitHitHexistingCount, der Unterschied besteht darin, dass Aufgaben, die bereits ein Fehlzündung haben, ignoriert werden.
• Misfire_Instruction_Smart_Policy Alle Fehlfeuer -Standardwerte des Triggers sind dies, was ungefähr "die Verarbeitungslogik dem intelligenten Quartz überlassen kann". Die grundlegende Strategie ist.
• Wenn der Zeitplan nur einmal ausgeführt wird, verwenden Sie Misfire_Instruction_Fire_Now.
• Wenn es sich um eine unendliche Planung handelt (RepeatCount ist unendlich), verwenden Sie MISFIRE_INSTRUCTION_RESCHANDULE_NEXT_WITH_REMING_COUNT.
• Andernfalls ist die Verwendung von MISFIRE_INSTRUCTION_RESCHANDULE_NOW_WITH_EXISTING_REPEAT_COUNT FREIFIRE ziemlich kompliziert, Sie können sich auf diesen Artikel beziehen.
Kalender
Der Kalender hier ist nicht JDKs java.util.calendar, nicht zur Berechnung von Daten. Seine Funktion ist es, die Zeit des Abzugs zu ergänzen. Bestimmte Zeitpunkte können ausgeschlossen oder hinzugefügt werden.
"Die automatische Rückzahlung der Kartenschulden am 25. eines jeden Monats um 0:00 Uhr" als Beispiel möchten wir den Zeitpunkt vom 25. Februar eines jeden Jahres ausschließen (da es 2,14 im Februar auf jeden Fall bankrott gehen wird). Diese Zeit kann durch Kalender erreicht werden.
Beispiel:
JährlichCalendar cal = new jährliches Calendar (); // Definieren Sie einen Kalender, der jedes Jahr mit einer Genauigkeit von Tagen ausgeführt wird, dh erst um 14:00 Uhr auf 2.25 Java.util.Calendar ausgeschlossen werden = neuer Gregoriancalendar (); ausgeschlossen. // Ausschlussdatum 2.25 Scheduler.AddCalendar ("Febcal", Cal, False, False); // Scheduler schließt sich diesem Kalender an. .withSchedule (SimpleSchedule () .witherIntervalinsekunden (1) .repeatforever ()) .build ();Quartz bietet uns die folgenden Kalender. Beachten Sie, dass alle Kalender entweder ausgeschlossen oder einbezogen werden können, abhängig von:
• HolidayCalendar. Geben Sie ein bestimmtes Datum an, z. B. 20140613. Genauigkeit zum Himmel.
• DailyCalendar. Gibt den Zeitraum eines jeden Tages (REGENGESTARTINGTIME, RANGELLETTIME) an, das Format lautet HH: mm [: ss [: mmmm]]. Das heißt, die maximale Genauigkeit kann Millisekunden erreichen.
• Weelycalendar. Geben Sie den Tag der Woche jeder Woche an, der optionale Wert ist java.util.calendar.sunday. Genauigkeit ist Tag.
• Monatslycalendar. Geben Sie den Tag eines jeden Monats an. Optionale Werte sind 1-31. Genauigkeit ist Tag
• JAHRESCALENDAR. Geben Sie an, welchen Tag des Jahres. Die Verwendungsmethode ist wie im obigen Beispiel gezeigt. Genauigkeit ist Tag.
• Croncalendar. Gibt einen Cron -Ausdruck an. Die Genauigkeit hängt vom Cron -Ausdruck ab, dh die maximale Genauigkeit kann Sekunden erreichen.
Trigger -Implementierungsklasse
Quartz hat die folgenden Triggerimplementierungen:
Einfacher
Gibt Aufgaben an, die zu einem bestimmten Zeitpunkt beginnen und in einem bestimmten Zeitintervall (in Millisekunden) ausgeführt werden. Es eignet sich für ähnliche Aufgaben wie: Starten Sie um 9:00 Uhr und führen Sie alle 1 Stunde aus. Seine Eigenschaften sind:
• Wiederholungsinterval -Wiederholungsintervall
• Wiederholung der Anzahl der Wiederholungen. Die tatsächliche Anzahl der Ausführungen ist Wiederholung+1. Weil es zur Startzeit einmal ausgeführt wird. Gleiches gilt für die unten stehende RepeatCount -Eigenschaft.
Beispiel:
Kalendarintervaltrigger
Ähnlich wie bei Simpligger gibt es Aufgaben an, die zu einem bestimmten Zeitpunkt beginnen und in einem bestimmten Zeitintervall ausgeführt werden. Der Unterschied besteht jedoch darin, dass das durch Simpligger angegebene Zeitintervall Millisekunden ist und es keine Möglichkeit gibt, festzustellen, dass es alle zwei Monate ausgeführt wird (das monatliche Intervall ist kein fester Wert), während die durch Kalenderintervaltrigger unterstützten Intervalleinheiten Sekunden, Stunden, Tage, Tage, Jahre und Wochen enthalten. Im Vergleich zu Simpligger hat es zwei Vorteile: 1. Es ist bequemer. Wenn Sie beispielsweise alle 1 Stunde ausführen, müssen Sie nicht berechnen, wie viele Millisekunden 1 Stunde gleich sind. 2. unterstützt Intervalle, die nicht mit fester Länge festgelegt sind, wie z. B. Intervalle, die Monate und Jahre sind. Der Nachteil ist jedoch, dass die Genauigkeit nur Sekunden erreichen kann. Die geeignete Aufgabe ist ähnlich wie bei: Start um 9:00 Uhr und einmal pro Woche um 9:00 Uhr. Seine Eigenschaften sind:
• Intervallausführungsintervall
• Intervallunit -Einheiten des Ausführungsintervalls (Sekunden, Minuten, Stunden, Tage, Monate, Jahre, Wochen)
Beispiel:
CalendarIntervalsplane ().
DailytimeIntervaltrigger
Geben Sie an, dass die Aufgaben in bestimmten Abschnitten während eines bestimmten Zeitraums täglich ausgeführt werden. Und es kann bestimmte Wochen unterstützen. Die geeignete Aufgabe ist ähnlich wie: jeden Tag von 9:00 bis 18:00 Uhr, alle 70 Sekunden und nur von Montag bis Freitag ausgeführt. Seine Eigenschaften sind:
• Täglich Starttime -Day -Startzeit
• Endtimeofday Endzeit des Tages
• Tage der Woche in der Woche, um hingerichtet zu werden
• Intervallausführungsintervall
• Intervallunit -Einheiten des Ausführungsintervalls (Sekunden, Minuten, Stunden, Tage, Monate, Jahre, Wochen)
• Wiederholung der Anzahl der Wiederholungen
Beispiel:
DailytimeIntervalsschonedule (). Innere Valinhours (1) // Alle 1 Stunde ausführen. WithrepeatCount (100) // Wiederholen Sie bis zu 100 Mal (tatsächlich 100+1 -mal ausgeführt) .build (); DailyTimeIntervalSchedule (). Diese Methode berechnet den EndtimeOfday tatsächlich basierend auf StartTimeOfday+Intervall*count .ondaySoftheweek (Montag, Dienstag, Mittwoch, Donnerstag, Freitag) // Ausführen von Montag bis Freitag.
Crontrigger
Es ist für komplexere Aufgaben geeignet und unterstützt Syntax, die in Linux Cron tippt (und ist leistungsfähiger). Grundsätzlich deckt es die meisten (aber nicht alle) der oben genannten drei Auslöser ab - natürlich ist es auch schwieriger zu verstehen. Die geeigneten Aufgaben sind ähnlich wie: jeweils jeden Tag um 0:00, 9:00 und 18:00 Uhr. Seine Eigenschaften sind nur:
Cron -Ausdruck
Aber diese Darstellung selbst ist komplex genug. Nachfolgend finden Sie Anweisungen. Beispiel:
cronschedule ("0 0/2 8-17 * * *?") // jeden Tag alle 2 Minuten um 8: 00-17: 00 ausführen. * Mon .build ();Cron -Ausdruck
| Standort | Zeitdomäne | Zulässige Werte | Besonderer Wert |
| 1 | Zweite | 0-59 | , - * / |
| 2 | Minute | 0-59 | , - * / |
| 3 | Stunde | 0-23 | , - * / |
| 4 | Datum | 1-31 | , - *? / LWC |
| 5 | Monat | 1-12 | , - * / |
| 6 | Woche | 1-7 | , - *? / LC # |
| 7 | Jahr (optional) | 1-31 | , - * / |
• Asterisk (): Kann in allen Feldern verwendet werden, um jeden Moment im entsprechenden Zeitbereich darzustellen. Zum Beispiel bedeutet dies "pro Minute".
• Fragezeichen (?): Dieses Zeichen wird nur in den Feldern Datum und Woche verwendet und wird normalerweise als "bedeutungsloser Wert" angegeben, der einem Punktcharakter entspricht.
• Minus Zeichen (-): drückt einen Bereich aus. Wenn "10-12" im Stundenfeld verwendet wird, bedeutet dies von 10 bis 12 Punkten, dh 10,11,12;
• Comma (,): drückt einen Listenwert aus. Wenn "Mon, Mi, Fri" im Wochebereich verwendet wird, bedeutet dies Montag, Mittwoch und Freitag.
• Schrägstrich (/): x/y repräsentiert eine gleiche Abfolge, x ist der Startwert und y ist der inkrementelle Schrittwert. Wenn Sie 0/15 im Minute -Feld verwenden, wird es als 0, 15, 30 und 45 Sekunden ausgedrückt, während 5/15 5, 20, 35, 50 im Minute -Feld bedeutet, können Sie auch */y verwenden, was 0/Y entspricht.
• L: Dieser Charakter wird nur in den Feldern Datum und Woche verwendet, die die Bedeutung von "letztes" darstellt, aber es bedeutet in den beiden Feldern unterschiedlich. L In dem Datumsfeld zeigt sich der letzte Tag des Monats an, wie zumor. der 31. Januar und den 28. Februar, was kein Schaltjahr ist; Wenn L in der Woche verwendet wird, zeigt es den Samstag an, der 7 entspricht. Wenn L jedoch in der Woche in der Woche erscheint und einem Wert X vorangegangen ist, bedeutet dies "die letzten x Tage des Monats", zum Beispiel 6L bedeutet am letzten Freitag des Monats;
• W: Dieser Charakter kann nur im Datumsfeld erscheinen und ist eine Änderung des Vorderdatums, der den Arbeitstag angibt, der dem Datum am nächsten liegt. Zum Beispiel stellt 15W den nächsten Arbeitstag bis zum 15. des Monats dar. Wenn der 15. des Monats Samstag ist, passt er am Freitag, den 14., zu. Wenn der 15. des Monats am Sonntag ist, entspricht es am Montag, den 16., am Montag; Wenn der 15. des Monats am Dienstag ist, ist es Dienstag, den 15.. Es muss jedoch angemerkt werden, dass das zugeordnete Matching -Datum nicht in den Monat überschritten werden kann. Wenn Sie 1W angeben, wenn der 1. Tag am Samstag ist, passt das Ergebnis am Montag, dem 3., nicht am letzten Tag des letzten Monats. Eine W -Zeichenfolge kann nur ein einzelnes Datum angeben, kann jedoch keinen Datumsbereich angeben.
• LW -Kombination: LW kann im Datumsfeld verwendet werden, was den letzten Arbeitstag des Monats bedeutet. Pfundzeichen (#): Dieser Charakter kann nur im Bereich der Woche verwendet werden, der einen Arbeitstag des Monats darstellt. Zum Beispiel repräsentiert 6#3 den dritten Freitag des Monats (6 steht am Freitag dar,#3 repräsentiert momentan die dritte), während 4#5 den fünften Mittwoch im Monat darstellt, vorausgesetzt, der Monat hat nicht den fünften Mittwoch, wird ignoriert und nicht ausgelöst.
• C: Dieser Charakter wird nur in den Feldern Datum und Woche verwendet, was die Bedeutung von "Kalender" darstellt. Dies bedeutet das mit dem Plan verbundene Datum, und wenn das Datum nicht zugeordnet ist, entspricht es allen Daten im Kalender. Zum Beispiel entspricht 5c im Datumsfeld dem ersten Tag nach dem 5. Tag des Kalenders. 1C entspricht dem ersten Tag nach Sonntag im Wochenfeld.
Cron -Ausdrücke sind nicht empfindlich gegenüber Sonderzeichen und sind nicht empfindlich für die Abkürzung des englischen Falls der Woche. Einige Beispiele:
| Ausdruck | veranschaulichen |
| 0 0 12 * *? | Laufen Sie jeden Tag um 12 Uhr |
| 0 15 10? * * | Laufen Sie jeden Tag um 10:15 Uhr |
| 0 15 10 * *? | Laufen Sie jeden Tag um 10:15 Uhr |
| 0 15 10 * *? * | Laufen Sie jeden Tag um 10:15 Uhr |
| 0 15 10 * *? 2008 | Laufen Sie 2008 um 10:15 Uhr pro Tag |
| 0 * 14 * *? | Läuft jede Minute zwischen 14:00 Uhr und endet jeden Tag um 14:59 Uhr. |
| 0 0/5 14 * *? | Führen Sie jeden Tag alle 5 Minuten von 14:00 bis 15:00 Uhr ab 14:55 Uhr und enden Sie um 14:55 Uhr. |
| 0 0/5 14,18 * *? | Es läuft jeden Tag alle 5 Minuten von 14:00 bis 15:00 Uhr und fährt jeden Tag alle 5 Minuten von 18:00 bis 19:00 Uhr. |
| 0 0-5 14 * *? | Laufen Sie jede Minute jeden Tag von 14:00 bis 14:05 Uhr. |
| 0 10,44 14? 3 Mi | Laufen Sie jeden Mittwoch von 14:10 bis 14:44 einmal pro Minute. |
| 0 15 10? * Mon-Fr | Laufen Sie jeden Montag, Dienstag, Mittwoch, Donnerstag, Donnerstag und Freitag um 10:15 Uhr. |
| 0 15 10 15 * ? | 每月15日10:15分运行。 |
| 0 15 10 L * ? | 每月最后一天10:15分运行。 |
| 0 15 10 ? * 6L | 每月最后一个星期五10:15分运行。 |
| 0 15 10 ? * 6L 2007-2009 | 在2007,2008,2009年每个月的最后一个星期五的10:15分运行。 |
| 0 15 10 ? * 6#3 | 每月第三个星期五的10:15分运行。 |
JobDetail & Job
JobDetail是任务的定义,而Job是任务的执行逻辑。在JobDetail里会引用一个Job Class定义。一个最简单的例子:
public class JobTest { public static void main(String[] args) throws SchedulerException, IOException { JobDetail job=newJob() .ofType(DoNothingJob.class) //Check Job Class .withIdentity("job1", "group1") //Set name/group .withDescription("this is a test job") //Set description.usingJobData("age", 18) //Add attributes to ageJobDataMap .build(); job.getJobDataMap().put("name", "quertz"); //Add attribute name to JobDataMap //Define a SimpleTrigger trigger that executes once per second. Trigger trigger=newTrigger().startNow().withIdentity("trigger1") .withSchedule(simpleSchedule().withIntervalInSeconds(1) .repeatForever()) .build(); Scheduler sche=StdSchedulerFactory.getDefaultScheduler(); sche.scheduleJob(job, trigger); sche.start(); System.in.read(); sche.shutdown(); }}public class DoNothingJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("do nothing"); }}从上例我们可以看出,要定义一个任务,需要干几件事:
•创建一个org.quartz.Job的实现类,并实现实现自己的业务逻辑。比如上面的DoNothingJob。
•定义一个JobDetail,引用这个实现类
•加入scheduleJob Quartz调度一次任务,会干如下的事:
•JobClass jobClass=JobDetail.getJobClass()
•Job jobInstance=jobClass.newInstance()。所以Job实现类,必须有一个public的无参构建方法。
•jobInstance.execute(JobExecutionContext context)。JobExecutionContext是Job运行的上下文,可以获得Trigger、Scheduler、JobDetail的信息。
也就是说,每次调度都会创建一个新的Job实例,这样的好处是有些任务并发执行的时候,不存在对临界资源的访问问题――当然,如果需要共享JobDataMap的时候,还是存在临界资源的并发访问的问题。
JobDataMap
Job是newInstance的实例,那我怎么传值给它? 比如我现在有两个发送邮件的任务,一个是发给"liLei",一个发给"hanmeimei",不能说我要写两个Job实现类LiLeiSendEmailJob和HanMeiMeiSendEmailJob。实现的办法是通过JobDataMap。
每一个JobDetail都会有一个JobDataMap。JobDataMap本质就是一个Map的扩展类,只是提供了一些更便捷的方法,比如getString()之类的。
我们可以在定义JobDetail,加入属性值,方式有二:
•newJob().usingJobData("age", 18) //加入属性到ageJobDataMap
•job.getJobDataMap().put("name", "quertz"); //加入属性name到JobDataMap
然后在Job中可以获取这个JobDataMap的值,方式同样有二:
public class HelloQuartz implements Job { private String name; public void execute(JobExecutionContext context) throws JobExecutionException { JobDetail detail = context.getJobDetail(); JobDataMap map = detail.getJobDataMap(); //Method 1: Obtain JobDataMap System.out.println("say hello to " + name + "[" + map.getInt("age") + "]" + " at " + new Date()); } //Method 2: The setter method of the property will automatically inject the JobDataMap attribute into public void setName(String name) { this.name = name; }}对于同一个JobDetail实例,执行的多个Job实例,是共享同样的JobDataMap,也就是说,如果你在任务里修改了里面的值,会对其他Job实例(并发的或者后续的)造成影响。
除了JobDetail,Trigger同样有一个JobDataMap,共享范围是所有使用这个Trigger的Job实例。
Job并发
Job是有可能并发执行的,比如一个任务要执行10秒中,而调度算法是每秒中触发1次,那么就有可能多个任务被并发执行。
有时候我们并不想任务并发执行,比如这个任务要去”获得数据库中所有未发送邮件的名单“,如果是并发执行,就需要一个数据库锁去避免一个数据被多次处理。这个时候一个@DisallowConcurrentExecution解决这个问题。就是这样:
public class DoNothingJob implements Job { @DisallowConcurrentExecution public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("do nothing"); }}注意,@DisallowConcurrentExecution是对JobDetail实例生效,也就是如果你定义两个JobDetail,引用同一个Job类,是可以并发执行的。
JobExecutionException
Job.execute()方法是不允许抛出除JobExecutionException之外的所有异常的(包括RuntimeException),所以编码的时候,最好是try-catch住所有的Throwable,小心处理。
其他属性
•Durability(耐久性?) 如果一个任务不是durable,那么当没有Trigger关联它的时候,它就会被自动删除。
•RequestsRecovery 如果一个任务是"requests recovery",那么当任务运行过程非正常退出时(比如进程崩溃,机器断电,但不包括抛出异常这种情况),Quartz再次启动时,会重新运行一次这个任务实例。
可以通过JobExecutionContext.isRecovering()查询任务是否是被恢复的。
Scheduler
•Scheduler就是Quartz的大脑,所有任务都是由它来设施。
•Schduelr包含一个两个重要组件: JobStore和ThreadPool。
•JobStore是会来存储运行时信息的,包括Trigger,Schduler,JobDetail,业务锁等。它有多种实现RAMJob(内存实现),JobStoreTX(JDBC,事务由Quartz管理),JobStoreCMT(JDBC,使用容器事务),ClusteredJobStore(集群实现)、TerracottaJobStore(什么是Terractta)。
•ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务的都会由线程池执行。
SchedulerFactory
SchdulerFactory,顾名思义就是来用创建Schduler了,有两个实现:DirectSchedulerFactory和StdSchdulerFactory。前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz.properties(不存在就都使用默认值)配置来实例化Schduler。通常来讲,我们使用StdSchdulerFactory也就足够了。
SchdulerFactory本身是支持创建RMI stub的,可以用来管理远程的Scheduler,功能与本地一样,可以远程提交个Job什么的。DirectSchedulerFactory的创建接口:
/** * Same as * {@link DirectSchedulerFactory#createScheduler(ThreadPool threadPool, JobStore jobStore)}, * with the addition of specifying the scheduler name and instance ID. This * scheduler can only be retrieved via * {@link DirectSchedulerFactory#getScheduler(String)} * * @param schedulerName * The name for the scheduler. * @param schedulerInstanceId * The instance ID for the scheduler. * @param threadPool * The thread pool for executing jobs * @param jobStore * The type of job store * @throws SchedulerException * if initialization failed */ public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore) throws SchedulerException;StdSchdulerFactory的配置例子, 更多配置,参考Quartz配置指南:
org.quartz.scheduler.instanceName = DefaultQuartzSchedulerorg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = trueorg.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
三、Quartz 集成Spring
开发一个job类,普通java类,需要有一个执行的方法:
package com.tgb.lk.demo.quartz;import java.util.Date;public class MyJob { public void work() { System.out.println("date:" + new Date().toString()); }}把类放到spring容器中,可以使用配置也可以使用注解:
<bean id="myJob" />
配置jobDetail,指定job对象:
<!-- 配置jobDetail,指定job对象--> <bean id="accountJobDetail"> <property name="targetObject"> <ref bean="accountJob" /> </property> <property name="targetMethod"> <value>work</value> </property> </bean>
配置一个trigger,需要指定一个cron表达式,指定任务的执行时机:
<!-- accountTrigger 的配置--> <bean id="accountTrigger" > <property name="jobDetail"> <ref bean="accountJobDetail" /> </property> <property name="cronExpression"> <value>0/3 * * * * ?</value> </property> </bean>
配置调度工厂:
<!-- 启动触发器的配置开始--> <bean name="startQuertz" lazy-init="false" autowire="no" > <property name="triggers"> <list> <ref bean="myJobTrigger" /> </list> </property> </bean> <!-- 启动触发器的配置结束-->
项目启动,定时器开始执行。
四、分析不同定时任务优缺点,寻找一种符合你项目需求的定时任务Timer管理延时任务的缺陷
以前在项目中也经常使用定时器,比如每隔一段时间清理项目中的一些垃圾文件,每隔一段时间进行日志清理;然而Timer是存在一些缺陷的,因为Timer在执行定时任务时只会创建一个线程,所以如果存在多个任务,且任务时间过长,超过了两个任务的间隔时间,会发生一些缺陷
Timer当任务抛出异常时的缺陷
如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行
Timer执行周期任务时依赖系统时间
Timer执行周期任务时依赖系统时间,如果当前系统时间发生变化会出现一些执行上的变化,ScheduledExecutorService基于时间的延迟,不会由于系统时间的改变发生执行变化。
对异常的处理
Quartz的某次执行任务过程中抛出异常,不影响下一次任务的执行,当下一次执行时间到来时,定时器会再次执行任务;而TimerTask则不同,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务。
精确到和功能
Quartz每次执行任务都创建一个新的任务类对象,而TimerTask则每次使用同一个任务类对象。 Quartz可以通过cron表达式精确到特定时间执行,而TimerTask不能。Quartz拥有TimerTask所有的功能,而TimerTask则没有上述,基本说明了在以后的开发中尽可能使用ScheduledExecutorService(JDK1.5以后)替代Timer。
五、cron 在线表达式生成器http://cron.qqe2.com/附录cron 表达式
cron表达式用于配置cronTrigger的实例。cron表达式实际上是由七个子表达式组成。这些表达式之间用空格分隔。
•Seconds (秒)
•Minutes(分)
•Hours(小时)
•Day-of-Month (天)
•Month(月)
•Day-of-Week (周)
•Year(年)
例:"0 0 12 ? * WED” 意思是:每个星期三的中午12点执行。个别子表达式可以包含范围或者列表。例如:上面例子中的WED可以换成"MON-FRI","MON,WED,FRI",甚至"MON-WED,SAT"。子表达式范围:
•Seconds (0~59)
•Minutes (0~59)
•Hours (0~23)
•Day-of-Month (1~31,但是要注意有些月份没有31天)
•Month (0~11,或者"JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,DEC")
•Day-of-Week (1~7,1=SUN 或者"SUN, MON, TUE, WED, THU, FRI, SAT”)
•Year (1970~2099)
Cron表达式的格式:秒分时日月周年(可选)。
Field name | Allowed value | Allowed special characters ------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
字符含义:
•*:代表所有可能的值。因此,“*”在Month中表示每个月,在Day-of-Month中表示每天,在Hours表示每小时
•-:表示指定范围。
•,:表示列出枚举值。例如:在Minutes子表达式中,“5,20”表示在5分钟和20分钟触发。
•/:被用于指定增量。例如:在Minutes子表达式中,“0/15”表示从0分钟开始,每15分钟执行一次。"3/20"表示从第三分钟开始,每20分钟执行一次。和"3,23,43"(表示第3,23,43分钟触发)的含义一样。
•?:用在Day-of-Month和Day-of-Week中,指“没有具体的值”。当两个子表达式其中一个被指定了值以后,为了避免冲突,需要将另外一个的值设为“?”。例如:想在每月20日触发调度,不管20号是星期几,只能用如下写法:0 0 0 20 * ?,其中最后以为只能用“?”,而不能用“*”。
•L:用在day-of-month和day-of-week字串中。它是单词“last”的缩写。它在两个子表达式中的含义是不同的。
•在day-of-month中,“L”表示一个月的最后一天,一月31号,3月30号。
•在day-of-week中,“L”表示一个星期的最后一天,也就是“7”或者“SAT”
•如果“L”前有具体内容,它就有其他的含义了。例如:“6L”表示这个月的倒数第六天。“FRIL”表示这个月的最后一个星期五。
•注意:在使用“L”参数时,不要指定列表或者范围,这样会出现问题。
•W:“Weekday”的缩写。只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在day-of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日,即最后一个星期五。
•# :只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用"6#3" or "FRI#3"指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。
表达式例子:
0 * * * * ? 每1分钟触发一次
0 0 * * * ? 每天每1小时触发一次
0 0 10 * * ? 每天10点触发一次
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
0 30 9 1 * ? 每月1号上午9点半
0 15 10 15 * ? 每月15日上午10:15触发
*/5 * * * * ? 每隔5秒执行一次
0 */1 * * * ? 每隔1分钟执行一次
0 0 5-15 * * ? 每天5-15点整点触发
0 0/3 * * * ? 每三分钟触发一次
0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0 12 ? * WED 表示每个星期三中午12点
0 0 17 ? * TUES,THUR,SAT 每周二、四、六下午五点
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
0 0 23 L * ? 每月最后一天23点执行一次
0 15 10 L * ? 每月最后一日的上午10:15触发
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
0 15 10 * * ? 2005 2005年的每天上午10:15触发
0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
The above timed tasks (example explanation) in Java implementation web applications are all the content I share with you. Ich hoffe, Sie können Ihnen eine Referenz geben und ich hoffe, Sie können wulin.com mehr unterstützen.