Come impostare un timer in Java?

Come impostare un timer, diciamo per 2 minuti, per provare a connettersi a un database e poi lanciare un'eccezione se c'è qualche problema di connessione?

Soluzione

Quindi la prima parte della risposta è come fare ciò che l'argomento chiede, dato che questo era il modo in cui l'ho interpretato inizialmente e che alcune persone sembravano trovare utile. La domanda è stata poi chiarita e ho esteso la risposta per affrontarla.

Impostare un timer

Per prima cosa è necessario creare un Timer (io sto usando la versione java.util qui):

import java.util.Timer;

..

Timer timer = new Timer();

Per eseguire il compito una volta 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 far ripetere il compito dopo la durata si fa:

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

Fare il timeout di un compito

Per fare specificamente ciò che la domanda chiarita chiede, cioè tentare di eseguire un compito per un dato periodo di tempo, si potrebbe fare quanto segue:

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

Questo verrà eseguito normalmente con eccezioni se il compito viene completato entro 2 minuti. Se viene eseguito più a lungo di così, verrà lanciata la TimeoutException.

Un problema è che anche se si otterrà una TimeoutException dopo i due minuti, il compito continuerà effettivamente a funzionare, anche se presumibilmente una connessione al database o alla rete finirà per scadere e lanciare un'eccezione nel thread. Ma siate consapevoli che potrebbe consumare risorse fino a quando ciò accade.

Commentari (9)

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
Commentari (10)

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

Per esempio:

FutureTask task = new FutureTask(new Callable() {
  @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
}
Commentari (3)