ScheduleAtFixedRate vs ScheduleWithFixedDelay


117

Was ist der Hauptunterschied zwischen scheduleAtFixedRateundscheduleWithFixedDelay Methoden von ScheduledExecutorService ?

scheduler.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleAtFixedRate:    " + new Date());
    }
}, 1, 3L , SECONDS);

scheduler.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleWithFixedDelay: " + new Date());
    }
}, 1, 3L , SECONDS);

Sie drucken genau zur gleichen Zeit und scheinen genau im gleichen Intervall ausgeführt zu werden.

Antworten:


206

Versuchen Sie, einen Thread.sleep(1000);Aufruf innerhalb Ihrer run()Methode hinzuzufügen ... Grundsätzlich ist es der Unterschied zwischen dem Planen von etwas basierend darauf, wann die vorherige Ausführung endet und wann sie (logisch) beginnt .

Angenommen, ich plane einen Alarm mit einer festen Rate von einmal pro Stunde und jedes Mal , wenn er ausgelöst wird, trinke ich eine Tasse Kaffee, was 10 Minuten dauert. Angenommen, das beginnt um Mitternacht, ich hätte:

00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee

Wenn ich mit einer festen Verzögerung von einer Stunde plane, hätte ich:

00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee

Welches Sie wollen, hängt von Ihrer Aufgabe ab.


17
Was passiert im FixedRate-Szenario, wenn die Kaffeezubereitung länger als eine Stunde dauert?
Brett VanderVeen

5
@BrettVanderVeen: Ich glaube, das hängt vom jeweiligen Testamentsvollstrecker ab. Es wird geplant pünktlich - aber ob das ausführt , hängt davon ab , ob ein Thread zu diesem Testamentsvollstrecker zur Verfügung steht. Ich schlage vor, Sie experimentieren, um zu sehen, wie dies in verschiedenen Szenarien funktioniert.
Jon Skeet

8
@BrettVanderVeen Aus der Dokumentation : "Wenn eine Ausführung dieser Aufgabe länger als die Dauer dauert, werden nachfolgende Ausführungen möglicherweise zu spät gestartet, jedoch nicht gleichzeitig ausgeführt." Mit anderen Worten, eine konforme Implementierung würde nicht zulassen, dass die nächste ausgeführt wird, bis die vorherige abgeschlossen ist.
M. Justin

Können Sie einen Arbeitscode für die angezeigte Ausgabe (Kaffee) für einen Anfänger wie mich bereitstellen?
MuneshSingh

@MuneshSingh: Nicht in dieser Frage, in der erklärt wird, was der Unterschied zwischen der Planung mit einer festen Rate und der Planung mit einer festen Verzögerung ist. Sie würden dies jedoch sowieso nicht selbst implementieren - Sie würden die integrierten Executoren verwenden.
Jon Skeet

57

Visualisieren Sie Zeitreihen der Aufrufmethode scheduleAtFixedRate. Die nächsten Ausführungen beginnen sofort, wenn die letzte länger als die Dauer dauert. Andernfalls wird es nach Ablauf der Zeit gestartet.

Zeitreihe der AufrufplanAtFixedRate-Methode

Zeitreihen der Aufrufmethode scheduleWithFixedDelay. Die nächste Ausführung beginnt nach der Verzögerungszeit zwischen der Beendigung einer Ausführung und dem Beginn der nächsten, unabhängig von ihrer Ausführungszeit

Zeitreihen der AufrufzeitplanWithFixedDelay-Methode

Hoffnung kann dir helfen


Ich konnte das "zusätzliche" Wort im Zeitreihendiagramm "schedAtFixedRate" nicht verstehen.
MuneshSingh

1
@MuneshSingh Es soll zeigen, dass die Ausführungszeit der Aufgabe länger als geplant ist, daher "zusätzliche" Zeit benötigt und die nächste Ausführung sofort beginnt.
Viorel

@Viorel danke für die Klarstellung. Bedeutet das, dass "Periode" nicht genau eine feste Zeitverzögerung zwischen zwei aufeinanderfolgenden Ausführungen ist?
MuneshSingh

1
@MuneshSingh Der Zeitraum ist festgelegt, aber die aktuelle Aufgabe wird nicht gestoppt, sobald sie bestanden wurde. Es würde einfach keine Verzögerung zwischen diesem und dem nächsten Lauf geben. Wenn Sie ein "Timeout" erstellen möchten, möchten Sie möglicherweise die Zukunft beibehalten und sie in einem anderen Executor abbrechen. In einfachen Worten heißt es, die erste Ausführung und die nächste so bald wie möglich nach Ablauf der "Periode" zu starten .
Viorel

4

Die scheduleAtFixedRate()Methode erstellt eine neue Aufgabe und sendet sie in jedem Zeitraum an den Executor, unabhängig davon, ob die vorherige Aufgabe abgeschlossen wurde oder nicht .

Andererseits erstellt die scheduleWithFixedDelay()Methode eine neue Aufgabe, nachdem die vorherige Aufgabe abgeschlossen wurde .


Du hast zweimal geschrieben scheduleAtFixedRate:)
Vlad

3

Wenn Sie das Java-Dokument lesen, wird es klarer

ScheduledFuture ScheduleAtFixedRate (ausführbarer Befehl, lange Anfangsverzögerung, langer Zeitraum, TimeUnit-Einheit) Erstellt eine periodische Aktion und führt sie aus, die erst nach der angegebenen anfänglichen Verzögerung und anschließend mit dem angegebenen Zeitraum aktiviert wird. Das heißt, die Ausführung beginnt nach initialDelay, dann nach initialDelay + period, dann nach initialDelay + 2 * und so weiter.

ScheduledFuture ScheduleWithFixedDelay (Runnable-Befehl, Long InitialDelay, Long Delay, TimeUnit-Einheit) Erstellt und führt eine periodische Aktion aus, die erst nach der angegebenen Anfangsverzögerung und anschließend mit der angegebenen Verzögerung zwischen der Beendigung einer Ausführung und dem Beginn der nächsten aktiviert wird.


1

Es gibt einen Haken in ScheduleAtFixedRate. Wenn der erste Thread zu lange dauert und nicht in der angegebenen Dauer beendet wird, startet der zweite fortlaufende Thread nicht, sobald die erste Aufgabe abgeschlossen ist, und startet nicht sofort, während der erste Thread seine Aufgabe und die angegebene Dauer erreicht hat wurde abgelaufen. JVM entscheidet, wann die nächste Aufgabe ausgeführt wird.

Ich denke, das wird dir helfen, die Methode zu wählen, weil ich aus diesem Grund ein großes Problem habe


1
Was? JVM wird entscheiden? Was soll das überhaupt bedeuten? Es ist wahr, dass die ausführbare Datei nicht gleichzeitig mit sich selbst gemäß den Dokumenten ausgeführt wird, aber es wird vom Executor entschieden, der benutzerdefiniert ODER der Standard sein kann ScheduledThreadPoolExecutor(und letzterer hat ein genau definiertes Verhalten)
Ordous

Nein, ich habe ein ähnliches Problem in meiner Anwendung gefunden, bei dem ich ein Intervall von 15 Minuten angegeben habe und die erste Aufgabe nicht in 15 Minuten erledigt ist und 15,30 Sekunden dauert, sodass die zweite Aufgabe nicht sofort gestartet wurde, sondern erst nach 5 Minuten und einige Zeit danach 8 min und mir ist nicht bewusst, ob wir dieses Verhalten kontrollieren können, da dies kein Standardverhalten ist.
user1047873

Das klingt nach Warteschlangen für Lehrbuchaufgaben.
Ordous

Ja, es bedeutet nur, dass alle Threads in Ihrem Executor bereits damit beschäftigt sind, etwas zu tun, und Ihre Aufgabe in eine Warteschlange mit zu erledigenden Aufgaben gestellt wird. ( HINWEIS Sie müssen dies bestätigen, indem Sie entweder die Warteschlange oder die Ausführung der Executor-Threads überprüfen.) Wie Sie dies steuern, hängt davon ab, welche Art von Executor Sie haben. Möglicherweise möchten Sie nur für diese bestimmte Aufgabe einen separaten 1-Thread-Executor erstellen, der dann auf nichts wartet. Oder geben Sie Ihrem aktuellen Executor mehr Threads. Oder ändern Sie die Strategie.
Ordous

0

Schreiben wir ein einfaches Programm:

import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
    if (time >= 12_000L) {
        executor.shutdown()
    } else {
        Thread.sleep(2000L)
        val now = System.currentTimeMillis()
        time += now - start
        System.out.println("Total $time delay ${now - start}\n")
        start = now
    }
}, 0L, 1000L, TimeUnit.MILLISECONDS)

Und sehen Sie die Ergebnisse:

| scheduleWithFixedDelay |   scheduleAtFixedRate  |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001  | Total 2003 delay 2003  |
| Total 5002 delay 3001  | Total 4004 delay 2001  |
| Total 8003 delay 3001  | Total 6004 delay 2000  |
| Total 11003 delay 3000 | Total 8004 delay 2000  |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
|          ---           | Total 12005 delay 2000 |

HINWEIS Die Ausführungszeit ist länger als das Warten

ScheduleWithFixedDelay behält die Verzögerung bei
ScheduleAtFixedRate entfernt die Verzögerung


-1
scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println("runnable start"); try { Thread.sleep(5000);  System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
      e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);



     scheduledExecutorService.scheduleWithFixedDelay(() -> {
     System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
     e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);

Führen Sie es einfach aus, und Sie werden den Unterschied kennen. Danke dir


1
Bitte erläutern Sie auch, wie der Code das Problem des OP löst. :)
Yash
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.