Come impostare un timer in Java?


151

Come impostare un timer, ad esempio per 2 minuti, per provare a connettersi a un database, quindi generare un'eccezione in caso di problemi nella connessione?


1
Coul il PO chiarisce se desiderano semplicemente tentare l'azione per almeno 2 minuti, o se l'eccezione deve essere lanciata ora dopo i due minuti, anche se è attualmente in corso un tentativo di connessione
thecoshman

Risposte:


280

Quindi la prima parte della risposta è come fare ciò che il soggetto chiede in quanto questo è stato il modo in cui inizialmente l'ho interpretato e alcune persone sembravano trovare utili. Da allora la domanda è stata chiarita e ho esteso la risposta per risolverlo.

Impostazione di un timer

Per prima cosa devi creare un timer (sto usando la java.utilversione qui):

import java.util.Timer;

..

Timer timer = new Timer();

Per eseguire l'attività una volta che si dovrebbe fare:

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

Per ripetere l'operazione dopo la durata, è necessario:

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

Effettuare un timeout dell'attività

Per fare specificamente ciò che viene posta la domanda chiarita, ovvero il tentativo di eseguire un'attività per un determinato periodo di tempo, è possibile effettuare le seguenti operazioni:

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

Ciò verrà eseguito normalmente con eccezioni se l'attività viene completata entro 2 minuti. Se dura più a lungo, verrà lanciata TimeoutException.

Un problema è che sebbene dopo due minuti otterrai TimeoutException, l'attività continuerà effettivamente a essere eseguita , sebbene presumibilmente un database o una connessione di rete finiranno per scadere e generare un'eccezione nel thread. Ma attenzione, potrebbe consumare risorse fino a quando ciò non accadrà.


Oh, immagino che tu abbia sbagliato il mio problema, devo provare ripetutamente a connettermi al database ogni 2 minuti ogni volta
Ankita,

Mi dispiace, ma il mio requisito è che desidero concedere 2 minuti per connettersi al database e quindi verrà visualizzato un messaggio di errore. È come se volessi impostare un limite di tempo per provare a connettermi al database
Ankita,

7
LETTORI ATTENZIONE: questa risposta è palesemente sbagliata. Imposta un timer per attendere 2 minuti, quindi esegue una query DB dopo quel ritardo di 2 minuti, quindi lo esegue ripetutamente ogni 2 minuti. Quello che NON fa è eseguire subito la query DB e poi fallire dopo 2 minuti, il che è quello che penso sia la domanda (come chiarito nel commento).
AgilePro,

2
@AgilePro Era vero. Non ho risposto alla domanda come è stato alla fine dichiarato e ora l'ho aggiornato per risolverlo.
Andrewmu,

1
@ErnestasGruodis Le API principali elencano il costruttore come pubblico: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Potresti avere una classe Timer diversa nel tuo percorso di classe - prova java. util.Timer come la classe.
Andrewmu,

25

Usa questo

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 ... questo funzionerebbe tecnicamente, tranne per il fatto che non copre i casi limite, in cui il tempo si esaurisce mentre si esegue un sondaggio DB, che potrebbe essere richiesto dall'OP
thecoshman,

1
Questa è l'unica risposta corretta. Funzionerà su un singolo thread e calcolerà l'ora di fine senza deriva. L'uso di un TimerTask è esattamente la cosa sbagliata da fare in questo caso. Sono sorpreso da quanti esempi su StackOverflow suggeriscono questo stesso tipo di cose sbagliate.
AgilePro

1
@thecoshman - le implementazioni del timer NON interrompono l'operazione DB una volta che è in corso, né lo fa. In ogni caso, è possibile controllare solo l'ora in cui si avvia l'operazione DB. C'è un malinteso comune sul fatto che è necessario un "timer" per cronometrare le cose, ma non è così. Devi solo fare qualcosa e, utilizzando l'ora corrente, assicurati di non farlo troppo a lungo.
AgilePro

diciamo che devi restituire la connessione o lanciare dopo ESATTAMENTE due minuti, questo non funzionerà. lo farà se DOPO due minuti di tentativi di connessione non si è ancora riusciti a connettersi. In una situazione in cui il controllo della connessione richiede due settimane, ci vorrà così tanto tempo per generare un'eccezione.
thoshoshman,

14
Questo è in realtà uno stile di programmazione molto brutto, dal momento che il ciclo while funziona costantemente e verifica la presenza di roba ... male per la cpu e male per la durata della batteria.
Infinito

11

Ok, penso di aver capito il tuo problema ora. Puoi usare un Futuro per provare a fare qualcosa e poi andare in timeout dopo un po 'se non è successo nulla.

Per esempio:

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
}

Viene generata un'eccezione ma il programma non viene terminato. Aiutatemi in questo.
Ankita,

2
È possibile utilizzare la classe ExecutorService anziché Executor. Ha il metodo shutdown () per fermare l'esecutore.
Riti

1
Gli esecutori ingeriranno le eccezioni generate che non gestisci in modo specifico nel tuo Callable / Runnable. Se il Runnable / Callable non rileva e gestisce l'eccezione stessa e viene fornita all'utente rispetto al proprietario, è necessario eseguire la sottoclasse di ScheduledExecutorService e sovrascrivere afterExecute (assicurarsi di chiamare super.afterExecute ()). Il secondo argomento di afterExecute sarà il lancio dal 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); 

basta copiare il parassita sopra il codice funzionerà bene. Ho dato due volte 'tempo' prima è per la prima volta per eseguire questo codice e la seconda è per l'intervallo di tempo.
Mahadev Mane,

La documentazione per Timer consiglia invece di utilizzare il framework Executor. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna

1

[Android] se qualcuno sta cercando di implementare il timer su Android usando Java .

è necessario utilizzare il thread dell'interfaccia utente in questo modo per eseguire operazioni.

Timer timer = new Timer();
timer.schedule(new TimerTask() {
           @Override
            public void run() {
                ActivityName.this.runOnUiThread(new Runnable(){
                    @Override
                      public void run() {
                       // do something
                      }        
                });
            }
        }, 2000));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.