Jak ustawić timer w Javie?

151

Jak ustawić czasomierz, powiedzmy na 2 minuty, aby spróbować połączyć się z bazą danych, a następnie zgłosić wyjątek, jeśli jest jakiś problem w połączeniu?

Ankita
źródło
1
Coul the OP wyjaśnij, czy chcą wykonać prostą czynność przez co najmniej 2 minuty, czy też wyjątek musi zostać wyrzucony teraz później po dwóch minutach, nawet jeśli próba połączenia jest obecnie w toku
thecoshman

Odpowiedzi:

280

Tak więc pierwsza część odpowiedzi dotyczy tego, jak zrobić to, o co prosi temat, ponieważ tak to początkowo zinterpretowałem i kilka osób wydawało się być pomocne. Pytanie zostało wyjaśnione i rozszerzyłem odpowiedź, aby je rozwiązać.

Ustawianie timera

Najpierw musisz utworzyć Timer (używam java.utilwersji tutaj):

import java.util.Timer;

..

Timer timer = new Timer();

Aby uruchomić zadanie po wykonaniu następujących czynności:

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);

Aby zadanie było powtarzane po upływie czasu, który wykonasz:

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);

Wyznaczanie limitu czasu zadania

Aby konkretnie zrobić to, o co prosi wyjaśnione pytanie, czyli próbować wykonać zadanie przez określony czas, możesz wykonać następujące czynności:

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();
}

Będzie to wykonywane normalnie z wyjątkami, jeśli zadanie zakończy się w ciągu 2 minut. Jeśli będzie działać dłużej, zostanie zgłoszony wyjątek TimeoutException.

Jednym z problemów jest to, że chociaż po dwóch minutach otrzymasz wyjątek TimeoutException, zadanie będzie nadal działać , chociaż prawdopodobnie połączenie z bazą danych lub siecią w końcu przekroczy limit czasu i zgłosi wyjątek w wątku. Ale pamiętaj, że zanim to się stanie, może zużywać zasoby.

andrewmu
źródło
Och, chyba źle zrozumiałeś mój problem, muszę wielokrotnie próbować połączyć się z bazą danych do 2 minut za każdym razem
Ankita
Przepraszam, ale moim wymaganiem jest to, że chcę dać 2 minuty na połączenie się z bazą danych, a potem po prostu wyskoczy jakiś komunikat o błędzie, tak jakbym chciał ustawić limit czasu na próbę połączenia się z bazą danych
Ankita
7
OSTRZEŻENIE CZYTELNIKÓW: Ta odpowiedź jest rażąco błędna. Ustawia czasomierz tak, aby czekał 2 minuty, a następnie uruchamia zapytanie DB po tym 2-minutowym opóźnieniu, a następnie uruchamia je ponownie i ponownie co 2 minuty. To, czego NIE robi, to natychmiastowe uruchomienie zapytania DB, a następnie niepowodzenie po 2 minutach, co moim zdaniem jest tym, o co pytano (jak wyjaśniono w komentarzu).
AgilePro,
2
@AgilePro To była prawda. Nie odpowiedziałem na pytanie, tak jak zostało ostatecznie określone, a teraz zaktualizowałem je, aby rozwiązać ten problem.
andrewmu
1
@ErnestasGruodis Podstawowe interfejsy API wyświetlają konstruktor jako publiczny: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Możesz mieć inną klasę Timer w swojej ścieżce klas - spróbuj java. util.Timer jako klasa.
andrewmu
25

Użyj tego

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
źródło
1
hmm ... to technicznie by zadziałało, z wyjątkiem tego, że nie obejmuje skrajnych przypadków, w których kończy się czas, gdy wykonujesz ankietę DB, co może być wymagane przez OP
thecoshman
1
To jedyna poprawna odpowiedź. Będzie działać na jednym wątku i obliczy czas zakończenia bez dryftu. Używanie TimerTask jest w tym przypadku dokładnie niewłaściwą rzeczą. Zaskoczyło mnie, jak wiele przykładów na StackOverflow sugeruje ten sam rodzaj złej głowy.
AgilePro,
1
@thecoshman - implementacje timera NIE przerywają operacji DB, gdy jest ona w toku, ani tego nie robi. W każdym razie możesz kontrolować tylko czas rozpoczęcia operacji DB. Istnieje powszechne błędne przekonanie, że do odmierzania czasu potrzebny jest „zegar”, ale tak się nie dzieje. Musisz tylko coś ZROBIĆ i korzystając z aktualnego czasu upewnij się, że NIE ROBISZ TEGO zbyt długo.
AgilePro,
powiedzmy, że musisz albo zwrócić połączenie, albo wyrzucić po DOKŁADNIE dwóch minutach, to nie zadziała. tak się stanie, jeśli PO dwóch minutach próby połączenia nadal nie możesz się połączyć. W sytuacji, gdy sprawdzenie połączenia trwa, powiedzmy, dwa tygodnie, zgłoszenie wyjątku zajmie tyle czasu.
thecoshman,
14
W rzeczywistości jest to bardzo zły styl kodowania, ponieważ pętla while stale działa i sprawdza, czy coś jest ... złe dla procesora i źle dla żywotności baterii.
Infinite
11

Ok, myślę, że teraz rozumiem twój problem. Możesz użyć Future, aby spróbować coś zrobić, a następnie po pewnym czasie wygasnąć, jeśli nic się nie wydarzyło.

Na przykład:

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
źródło
Zgłoszono wyjątek, ale program nie zostaje zakończony. Proszę, pomóż mi w tym.
Ankita
2
Zamiast klasy Executor można użyć klasy ExecutorService. Posiada metodę shutdown () do zatrzymania executora.
Rites
1
Egzekutorzy będą połykać wyrzucane wyjątki, których specjalnie nie obsługujesz w swoim Wywołalnym / Wykonalnym. Jeśli Twój Runnable / Callable nie przechwytuje i nie obsługuje samego wyjątku, a jest on dostarczany do Ciebie, a nie do Ciebie, do którego jesteś właścicielem, musisz podklasować ScheduledExecutorService i przesłonić afterExecute (pamiętaj, aby wywołać super.afterExecute ()). Drugim argumentem do afterExecute będzie rzut z 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 Mane
źródło
po prostu skopiuj szkodnika powyżej kodu, będzie działał dobrze. Podałem dwa razy „czas”, po raz pierwszy na wykonanie tego kodu, a drugi na interwał.
Mahadev Mane
Dokumentacja dla Timer zaleca zamiast tego użycie struktury Executor. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna
1

[Android], jeśli ktoś chce zaimplementować zegar na Androida za pomocą java .

aby wykonywać operacje , potrzebujesz takiego wątku interfejsu użytkownika .

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
źródło