2010-08-03 37 views
19

Tener esta declaración de espera:¿Cómo diferenciar cuándo espera (tiempo de espera prolongado) salir para notificar o tiempo de espera?

public final native void wait(long timeout) throws InterruptedException; 

Podría salir por InterruptedException, o por el tiempo de espera, o porque Notificar/notifyAll método fue llamado en otro hilo, Excepción es fácil de coger, pero ...

Hay ¿Hay alguna forma de saber si la causa de las salidas fue el tiempo de espera o la notificación?

EDIT:

Ésta es una manera complicada que podría funcionar, (aunque no me gusta)

  long tBefore=System.currentTimeMillis(); 
      wait(TIMEOUT); 
      if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
      { 
       //timeout 
      } 
+2

Tuve una necesidad similar y en mi caso resultó que un 'Semaphore' era más adecuado; 'Semaphore.tryAcquire (long timeout, TimeUnit unit)' devuelve 'false' si ha transcurrido el tiempo de espera. – Santosh

+0

Semaphore funcionaría a menos que necesite tener la capacidad de esperar, lo cual no es compatible con el contrato público de Semaphore. –

Respuesta

7

No se puede diferenciar entre los dos menos que proporcione alguna adicional código. Por ejemplo, mediante la adición de un ThreadLocalBoolean que se establece en true sólo en notify()

Pero primero debe asegurarse de que su lógica requiere esta diferenciación.

+4

El OP ya sabía que no se lanzaría una excepción y desea distinguir entre un tiempo de espera y una notificación. Esto no proporciona ninguna información útil para ese fin. –

+1

gracias, malentendí el OP. Actualizado ahora – Bozho

+0

+1 para reescribir, y sí un booleano, es un método sincronizado lo que estoy usando ahora –

1

No se emite ninguna excepción en notificación y tiempo de espera.

Creo que es mejor confiar en java.lang.concurrent objetos de sincronización de paquetes en lugar de usar Object.wait().

12

Esto no responde exactamente la pregunta, pero probablemente resolverá su problema: utilice mecanismos de concurrencia de mayor nivel. Wait/notify suele ser de un nivel más bajo de lo que desearía, por este motivo, entre muchos otros.

Por ejemplo, si usaba BlockingQueue.poll(long, TimeUnit), podría verificar si el resultado es nulo para saber si ha excedido el tiempo de espera.

16

Hay una razón más por la que puede regresar la notificación: activación espuria. Esto es poco probable pero posible, ya que la prevención de activaciones espúreas es muy costosa en algunas combinaciones de hardware/sistema operativo.

Debido a esto, siempre debe llamar a wait() en un bucle y volver a verificar la condición que está esperando. Durante este trabajo, es fácil verificar el tiempo de espera al mismo tiempo.

Para más detalles, recomiendo el libro "Java Concurrency In Practice". Y usando construcciones de mayor nivel que harán que todo esto sea correcto para ti.

+0

+1 Voy a tener en cuenta esas falsa activación –

2

No hay forma de saber directamente, es decir, debería agregar código adicional para determinar esto. A menudo, cuando esperas(), estás esperando que ocurra algo que cambie el estado de un objeto de alguna manera, por ejemplo, estableciendo una variable booleana, tal vez. Si ese es el caso, entonces puede simplemente verificar el estado de esa variable para ver si ocurrió el evento, o simplemente agotó el tiempo de espera. O puede ver el valor de System.currentTimeMillis() para ver si el tiempo transcurrido es mayor o igual que el período de tiempo de espera; si lo es, sería una pista que probablemente haya agotado el tiempo de espera (aunque no es una garantía absoluta) O si el tiempo transcurrido es menor que el tiempo de espera, entonces no habrá agotado el tiempo de espera. ¿Eso ayuda?

+0

En realidad estoy usando currentTimeMillis(), pero me preguntaba si había alguna forma mejor –

+0

@ Hernán Eche Como he puesto en mi respuesta, no es una garantía absoluta. si puede decir, ¿por qué quiere identificar si se agotó el tiempo de espera? Podemos buscar alguna solución. – YoK

+0

sí, sé que no es un enfoque muy bueno, lo uso para un ciclo mientras (verdadero) {espera (tiempo de espera); otras tareas..; } para que pueda salir del bucle cuando realmente se notificó la espera, por ejemplo, si wait devolvería boolean, sería algo así como while (true) {if (wait (timeout)) break; otras tareas..; } de todos modos encapsularé todo dentro de una clase y una bandera con método sincronizado para esperar/notificar en paralelo con la configuración de esta bandera –

3

No utilice System.currentTimeMillis(), use System.nanoTime() en su lugar.

El primero mide el tiempo absoluto (basado en el reloj del sistema) y puede tener resultados curiosos si se cambia la hora del sistema. Por ejemplo: una espera de 5 segundos puede tener una duración de una hora si el reloj se mueve hacia atrás una hora, o una espera de 10 minutos después de 0 segundos si el reloj se mueve hacia adelante.

El segundo mide el tiempo relativo. Siempre se ejecutará en una dirección a velocidad constante, pero no tiene origen. Eso significa que los valores solo se pueden usar para medir el tiempo relativo, pero pueden y no deben usarse para determinar una fecha.