¿Cómo configurar un temporizador en Java?

151

¿Cómo configurar un temporizador, digamos durante 2 minutos, para intentar conectarse a una base de datos y luego lanzar una excepción si hay algún problema en la conexión?

Ankita
fuente
1
Coul the OP aclara si desean simplemente intentar la acción durante al menos 2 minutos, o si la excepción debe ser lanzada ahora más tarde en los dos minutos, incluso si un intento de conexión está actualmente en curso
thecoshman

Respuestas:

280

Entonces, la primera parte de la respuesta es cómo hacer lo que el sujeto pregunta, ya que así fue como lo interpreté inicialmente y algunas personas parecieron encontrar útil. La pregunta se aclaró desde entonces y he extendido la respuesta para abordar eso.

Configurar un temporizador

Primero necesitas crear un temporizador (estoy usando la java.utilversión aquí):

import java.util.Timer;

..

Timer timer = new Timer();

Para ejecutar la tarea una vez que lo haría:

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

Para que la tarea se repita después de la duración que haría:

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

Hacer un tiempo de espera de tarea

Para hacer específicamente lo que pide la pregunta aclarada, que es intentar realizar una tarea durante un período de tiempo determinado, puede hacer lo siguiente:

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

Esto se ejecutará normalmente con excepciones si la tarea se completa en 2 minutos. Si dura más que eso, se lanzará la TimeoutException.

Un problema es que, aunque obtendrá una TimeoutException después de los dos minutos, la tarea continuará ejecutándose , aunque presumiblemente una base de datos o una conexión de red finalmente agotarán el tiempo y generarán una excepción en el hilo. Pero tenga en cuenta que podría consumir recursos hasta que eso suceda.

andrewmu
fuente
Oh, supongo que te equivocaste, tengo que intentar conectarme repetidamente a la base de datos hasta 2 minutos cada vez
Ankita
Lo siento, pero mi requisito es que quiero dar 2 minutos para conectarme a la base de datos y luego arrojará un mensaje de error. Es como si quisiera establecer un límite de tiempo para intentar conectarme a la base de datos
Ankita
77
LECTORES CUIDADO: Esta respuesta es descaradamente incorrecta. Establece un temporizador para esperar 2 minutos, y luego ejecuta una consulta DB después de ese retraso de 2 minutos, y luego lo ejecuta una y otra vez cada 2 minutos. Lo que NO hace es ejecutar la consulta DB de inmediato y luego fallar después de 2 minutos, que es lo que creo que se hizo la pregunta (como se aclara en el comentario).
AgilePro
2
@AgilePro Eso fue cierto. No respondí la pregunta ya que finalmente se dijo y ahora la actualicé para abordar eso.
andrewmu
1
@ErnestasGruodis Las API principales enumeran el constructor como público: docs.oracle.com/javase/7/docs/api/java/util/Timer.html#Timer () Es posible que tenga una clase de temporizador diferente en su classpath: pruebe java. Util.Timer como la clase.
andrewmu
25

Utilizar este

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
fuente
1
hmm ... esto funcionaría técnicamente, excepto que no cubre los casos límite, en los que se acaba el tiempo
mientras
1
Esta es la única respuesta correcta. Se ejecutará en un solo hilo y calculará el tiempo de finalización sin deriva. Usar un TimerTask es exactamente lo incorrecto en este caso. Me sorprende la cantidad de ejemplos en StackOverflow que sugieren este mismo tipo de cosas equivocadas.
AgilePro
1
@thecoshman: las implementaciones del temporizador NO interrumpen la operación de DB una vez que está en progreso, ni lo hace. En cualquier caso, solo puede controlar el tiempo que inicia la operación de DB. Existe una idea errónea común de que necesita un "temporizador" para cronometrar las cosas, pero no lo hace. Solo necesita HACER algo, y al usar la hora actual, asegúrese de no HACERLO demasiado tiempo.
AgilePro
supongamos que tiene que devolver la conexión o lanzar después EXACTAMENTE dos minutos, esto no funcionará. lo hará si DESPUÉS de dos minutos de intentar conectarse aún no ha podido conectarse. En una situación en la que la verificación de la conexión demora, por ejemplo, dos semanas, esto tomará tanto tiempo para generar una excepción.
thecoshman
14
En realidad, este es un estilo de codificación muy malo, ya que el ciclo while se ejecuta constantemente y busca cosas ... malo para la CPU y malo para la vida útil de la batería.
Infinito
11

Ok, creo que entiendo tu problema ahora. Puede usar un Futuro para intentar hacer algo y luego agotar el tiempo de espera después de un tiempo si no ha sucedido nada.

P.ej:

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
fuente
Se produce una excepción pero el programa no se termina. Por favor, ayúdenme a superar esto.
Ankita
2
Puede usar la clase ExecutorService en lugar de Executor. Tiene el método shutdown () para detener al ejecutor.
Ritos
1
Los ejecutores tragarán excepciones lanzadas que no manejas específicamente en tu Callable / Runnable. Si su Runnable / Callable no detecta y maneja la excepción en sí y se le proporciona a usted frente a su propietario, entonces debe subclasificar el ScheduledExecutorService y anular afterExecute (asegúrese de llamar a super.afterExecute ()). El segundo argumento para afterExecute será el que se puede lanzar desde Runnable / Callable
adam el
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
fuente
simplemente copie la plaga sobre el código, funcionará bien. Le he dado dos veces 'tiempo' primero es por primera vez para ejecutar este código y segundo es por tiempo de intervalo.
Mahadev Mane
La documentación para Timer recomienda usar el marco Ejecutor en su lugar. docs.oracle.com/javase/10/docs/api/java/util/Timer.html
Karan Khanna
1

[Android] si alguien busca implementar un temporizador en Android usando Java .

necesita usar un hilo de interfaz de usuario como este para realizar operaciones.

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
fuente