2010-09-02 12 views
11

Me gustaría saber si Java proporciona un equivalente de las clases .NET de ManualResetEvent y WaitHandle, ya que me gustaría escribir el código que bloquea un tiempo de espera dado a menos que se desencadene un evento.Java Equivalente de .NET's ManualResetEvent y WaitHandle

Las clases .NET de WaitHandle y ManualResetEvent proporcionan una interfaz agradable y libre de problemas para lo que también es seguro para subprocesos hasta donde yo sé, entonces, ¿qué tiene Java para ofrecer?

Respuesta

14

Ha considerado el uso wait/notify (el equivalente a Monitor.Wait y Monitor.Pulse) en su lugar?

Querrá comprobar un poco si en realidad necesita esperar (para evitar condiciones de carrera) pero debería funcionar.

De lo contrario, algo como CountDownLatch bien puede hacer lo que desee.

EDIT: Acabo de notar que CountDownLatch es básicamente de "uso único" - no se puede restablecer el conteo más tarde, por lo que puedo ver. Es posible que desee Semaphore en su lugar. Utilice tryAcquire como éste para que retenga un tiempo de espera:

if (semaphore.tryAquire(5, TimeUnit.SECONDS)) { 
    ... 
    // Permit was granted before timeout 
} else { 
    // We timed out while waiting 
} 

Tenga en cuenta que esto es a diferencia de ManualResetEvent hecho de que cada llamada con éxito a tryAcquire reducirá el número de permisos - por lo que finalmente van a correr de nuevo. No puede hacer que se "establezca" permanentemente como podría con ManualResetEvent. (Eso sería trabajar con CountdownLatch, pero entonces no podría "reset" it :)

+0

Pero, ¿y el aspecto del tiempo de espera? Por lo que leí en la documentación de CountDownLatch, no parece tener un valor de tiempo de espera que pueda interceptar o detener antes de que se agote el tiempo de espera hasta el final. Me gustaría tener un tipo de Java que pueda usar para esperar un tiempo de espera, y que pueda ser interceptado antes de que termine el tiempo de espera, como una anulación manual. ¡También, hola Sr. Skeet! ¿Como estas? Probablemente obtienes mucho, ¡pero tu libro es genial! – Orca

+0

@Voulnet: Llamarías a 'await (tiempo de espera prolongado, unidad TimeUnit)' - que bloqueará durante la duración de tiempo de espera dada * o * regresará antes si el bloqueo se cuenta hacia abajo. Me alegra que te guste el libro :) –

+0

Sí , la solución debe funcionar de maravilla ya que solo tengo un objeto esperando en cualquier momento. Gracias, Sr. Jon Skeet. – Orca

2

Desde: http://www.experts-exchange.com/Programming/Languages/Java/Q_22076798.html

Hola, se puede lograr la sincronización utilizando la clase java.util.concurrent.Semaphore (0 permiso de uso)

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Semaphore.html

siguiente ejemplo muestra cómo resolver el primer problema de sincronización, y el otro será similar:

import java.util.concurrent.Semaphore; 

class ScalesCommunication { 

    private static Semaphore sem = new Semaphore(0); 

    // called by thread 1 
    void readLoop() { 
     //... 

     //after connection established, release semaphore (value incremented by 1) 
     sem.release(); 
    } 

    // called by thread 2 
    String sendCommand(String command) { 

     sem.acquire(); // thread waits here if sem value == 0 

     // at this point connection is established 
     //... 
    } 
} 
4
class ManualResetEvent { 

    private final Object monitor = new Object(); 
    private volatile boolean open = false; 

    public ManualResetEvent(boolean open) { 
    this.open = open; 
    } 

    public void waitOne() throws InterruptedException { 
    synchronized (monitor) { 
     while (open==false) { 
      monitor.wait(); 
     } 
    } 
    } 

    public void set() {//open start 
    synchronized (monitor) { 
     open = true; 
     monitor.notifyAll(); 
    } 
    } 

    public void reset() {//close stop 
    open = false; 
    } 
} 
+0

Tenga en cuenta que contiene un error desagradable: si 'waitOne()' se invoca antes de 'set()', se ingresará el 'monitor' y se bloqueará una llamada a' set() ', lo que provocará un interbloqueo. Mi solución hacky era llamar a 'monitor.wait (10)' en un bucle que sale de la sincronización en cada iteración. –

+0

En realidad, podría estar equivocado al respecto porque aparentemente el monitor debería ser liberado durante la espera, aunque mis pruebas mostraron un punto muerto definitivo. Independientemente, he cambiado a usar 'Semaphore' para mi caso de uso. –

+0

¿podría obtener sus pruebas con un punto muerto? – user249654

1

En teoría, la clase ManualResetEvent como corresponde a la verdad en Java 5 (pero no antes). Dada la larga historia de implementaciones incorrectas (o inadecuadas) de volátiles, me parece más inteligente agregar un bloque sincronizado adicional en el reinicio() para generar una barrera de escritura garantizada y garantizar la atomicidad completa. El peligro es que una lectura de "abrir" puede pasar una escritura de "abrir" en multiprocesador Intel cpus. La ventaja del cambio que se detalla a continuación: puede no ser óptimamente eficiente, pero tiene la gran ventaja de garantizar que no está mal, a un costo adicional muy bajo.

class ManualResetEvent { 
     private final Object monitor = new Object(); 
     private volatile boolean open = false; 

     public ManualResetEvent(boolean open) { 
     this.open = open; } 

     public void waitOne() throws InterruptedException { 
     synchronized (monitor) { 
      while (open==false) { 
       monitor.wait(); 
      } 
     } 
     } 

     public void set() {//open start 
     synchronized (monitor) { 
      open = true; 
      monitor.notifyAll(); 
     } 
     } 

     public void reset() {//close stop 
     synchronized(monitor) { 
      open = false; 
     } 
     } 
    } 

Gracias al póster original.