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?


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.


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

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
}

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

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));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.