Wie stelle ich einen Timer in Java ein?

151

Wie kann man einen Timer einstellen, beispielsweise für 2 Minuten, um zu versuchen, eine Verbindung zu einer Datenbank herzustellen, und dann eine Ausnahme auslösen, wenn ein Verbindungsproblem vorliegt?

Ankita
quelle
1
Lassen Sie das OP klären, ob sie die Aktion einfach mindestens 2 Minuten lang versuchen
möchten

Antworten:

280

Der erste Teil der Antwort ist also, wie man das macht, was das Thema verlangt, da ich es anfangs so interpretiert habe und einige Leute es als hilfreich empfanden. Die Frage wurde inzwischen geklärt und ich habe die Antwort erweitert, um dies zu beheben.

Timer einstellen

Zuerst müssen Sie einen Timer erstellen (ich verwende die java.utilVersion hier):

import java.util.Timer;

..

Timer timer = new Timer();

So führen Sie die Aufgabe aus, sobald Sie Folgendes tun würden:

timer.schedule(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000);
// Since Java-8
timer.schedule(() -> /* your database code here */, 2*60*1000);

So wiederholen Sie die Aufgabe nach der Dauer, die Sie ausführen würden:

timer.scheduleAtFixedRate(new TimerTask() {
  @Override
  public void run() {
    // Your database code here
  }
}, 2*60*1000, 2*60*1000);

// Since Java-8
timer.scheduleAtFixedRate(() -> /* your database code here */, 2*60*1000, 2*60*1000);

Zeitüberschreitung für Aufgaben

Um genau das zu tun, was in der geklärten Frage gestellt wird, dh zu versuchen, eine Aufgabe für einen bestimmten Zeitraum auszuführen, können Sie Folgendes tun:

ExecutorService service = Executors.newSingleThreadExecutor();

try {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            // Database task
        }
    };

    Future<?> f = service.submit(r);

    f.get(2, TimeUnit.MINUTES);     // attempt the task for two minutes
}
catch (final InterruptedException e) {
    // The thread was interrupted during sleep, wait or join
}
catch (final TimeoutException e) {
    // Took too long!
}
catch (final ExecutionException e) {
    // An exception from within the Runnable task
}
finally {
    service.shutdown();
}

Dies wird mit Ausnahmen normal ausgeführt, wenn die Aufgabe innerhalb von 2 Minuten abgeschlossen ist. Wenn es länger läuft, wird die TimeoutException ausgelöst.

Ein Problem ist, dass die Task zwar nach zwei Minuten eine TimeoutException erhält, die Task jedoch weiterhin ausgeführt wird , obwohl vermutlich eine Datenbank- oder Netzwerkverbindung irgendwann eine Zeitüberschreitung aufweist und eine Ausnahme in den Thread auslöst. Beachten Sie jedoch, dass dies bis dahin Ressourcen verbrauchen kann.

andrewmu
quelle
Oh, ich denke, Sie haben mein Problem falsch verstanden. Ich muss wiederholt versuchen, jedes
Mal
Es tut mir leid, aber meine Anforderung ist, dass ich 2 Minuten Zeit geben möchte, um eine Verbindung zur Datenbank herzustellen, und dann wird nur eine Fehlermeldung ausgegeben. Es ist, als ob ich ein Zeitlimit festlegen möchte, um zu versuchen, eine Verbindung zur Datenbank
herzustellen
7
LESER VORSICHT: Diese Antwort ist offensichtlich falsch. Es legt einen Timer fest, der 2 Minuten wartet, und führt dann nach dieser 2-minütigen Verzögerung eine DB-Abfrage aus. Anschließend wird sie alle 2 Minuten immer wieder ausgeführt. Was es NICHT tut, ist, die DB-Abfrage sofort auszuführen und dann nach 2 Minuten auszufallen, was meiner Meinung nach die gestellte Frage ist (wie im Kommentar erläutert).
AgilePro
2
@ AgilePro Das war wahr. Ich habe die Frage nicht beantwortet, da sie schließlich angegeben wurde, und ich habe sie jetzt aktualisiert, um dies zu beheben.
Andrewmu
1
@ErnestasGruodis Die Kern-APIs listen den Konstruktor als öffentlich auf: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Möglicherweise haben Sie eine andere Timer-Klasse in Ihrem Klassenpfad - versuchen Sie es mit Java. util.Timer als Klasse.
Andrewmu
25

Benutze das

long startTime = System.currentTimeMillis();
long elapsedTime = 0L.

while (elapsedTime < 2*60*1000) {
    //perform db poll/check
    elapsedTime = (new Date()).getTime() - startTime;
}

//Throw your exception
nimWM
quelle
1
hmm ... das würde technisch funktionieren, außer es deckt keine
Randfälle ab
1
Dies ist die einzig richtige Antwort. Es läuft auf einem einzelnen Thread und berechnet die Endzeit ohne Drift. Die Verwendung einer TimerTask ist in diesem Fall genau das Falsche. Ich bin überrascht, wie viele Beispiele auf StackOverflow diese Art von falschem Kopf suggerieren.
AgilePro
1
@thecoshman - Die Timer-Implementierungen unterbrechen den DB-Vorgang NICHT, sobald er ausgeführt wird, und dies auch nicht. In jedem Fall können Sie nur die Zeit steuern, zu der Sie den DB-Vorgang starten. Es gibt ein weit verbreitetes Missverständnis, dass Sie einen "Timer" benötigen, um die Zeit zu bestimmen, aber Sie tun es nicht. Sie müssen nur etwas tun, und indem Sie die aktuelle Zeit verwenden, stellen Sie sicher, dass Sie es nicht zu lange tun.
AgilePro
Angenommen, Sie müssen entweder die Verbindung zurückgeben oder nach genau zwei Minuten werfen. Dies funktioniert nicht. Dies wird der Fall sein, wenn Sie nach zwei Minuten des Verbindungsversuchs immer noch keine Verbindung hergestellt haben. In einer Situation, in der die Verbindungsprüfung beispielsweise zwei Wochen dauert, dauert es so lange, bis eine Ausnahme ausgelöst wird.
Thecoshman
14
Dies ist eigentlich ein sehr schlechter Codierungsstil, da die while-Schleife ständig läuft und nach Dingen sucht ... schlecht für die CPU und schlecht für die Akkulaufzeit.
Unendlich
11

Ok, ich glaube ich verstehe dein Problem jetzt. Sie können eine Zukunft verwenden, um zu versuchen, etwas zu tun, und dann nach einer Weile eine Zeitüberschreitung, wenn nichts passiert ist.

Z.B:

FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
  @Override
  public Void call() throws Exception {
    // Do DB stuff
    return null;
  }
});

Executor executor = Executors.newSingleThreadScheduledExecutor();
executor.execute(task);

try {
  task.get(5, TimeUnit.SECONDS);
}
catch(Exception ex) {
  // Handle your exception
}
andrewmu
quelle
Ausnahme wird ausgelöst, aber das Programm wird nicht beendet. Bitte helfen Sie mir dabei.
Ankita
2
Sie können die ExecutorService-Klasse anstelle von Executor verwenden. Es hat die shutdown () -Methode, um den Executor zu stoppen.
Riten
1
Executoren schlucken ausgelöste Ausnahmen, die Sie in Ihrem Callable / Runnable nicht speziell behandeln. Wenn Ihr Runnable / Callable die Ausnahme selbst nicht abfängt und behandelt und Ihnen im Vergleich zu Ihrem Eigentümer zur Verfügung gestellt wird, müssen Sie den ScheduledExecutorService in eine Unterklasse unterteilen und afterExecute überschreiben (stellen Sie sicher, dass Sie super.afterExecute () aufrufen). Das zweite Argument für afterExecute ist das Throwable aus dem Runnable / Callable
Adam
3
    new java.util.Timer().schedule(new TimerTask(){
        @Override
        public void run() {
            System.out.println("Executed...");
           //your code here 
           //1000*5=5000 mlsec. i.e. 5 seconds. u can change accordngly 
        }
    },1000*5,1000*5); 
Mahadev Mähne
quelle
Kopieren Sie einfach den Schädling über den Code, es wird gut funktionieren. Ich habe zweimal "Zeit" angegeben, zum einen zum ersten Mal, um diesen Code auszuführen, und zum anderen für die Intervallzeit.
Mahadev Mane
In der Dokumentation zu Timer wird empfohlen, stattdessen das Executor-Framework zu verwenden. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna
1

[Android] wenn jemand Timer mit Java auf Android implementieren möchte .

Sie müssen einen solchen UI-Thread verwenden , um Vorgänge auszuführen.

Timer timer = new Timer();
timer.schedule(new TimerTask() {
           @Override
            public void run() {
                ActivityName.this.runOnUiThread(new Runnable(){
                    @Override
                      public void run() {
                       // do something
                      }        
                });
            }
        }, 2000));
Abhishek Garg
quelle