2009-06-30 10 views

Respuesta

16

Lo más cercano que conozco es el Semaphore. Simplemente úselo con un "permiso" de 1, y aquire/release será prácticamente el mismo que el ManualResetEvent.

Un semáforo inicializado a uno, y que se utiliza tal que sólo tiene al más un permiso disponible, puede servir como un bloqueo de exclusión mutua. Esto es más conocido como semáforo binario , porque solo tiene dos estados : un permiso disponible o cero permisos disponibles. Cuando se usa de esta manera , el semáforo binario tiene la propiedad (a diferencia de muchos de bloqueo implementaciones), que el "bloqueo" puede ser liberado de un hilo que no sea el propietario (como semáforos no tienen noción de propiedad). Esto puede ser útil en algunos contextos especializados , como la recuperación de bloqueo .

+0

No creo que esto pueda funcionar sin una condición de carrera (suponiendo que un hilo no puede liberar un semáforo que no se adquirió previamente) – ripper234

+1

Lo llevo de vuelta: según la documentación que aparece, se puede liberar un semáforo sin siquiera tomarlo. – ripper234

+3

Sí, eso es porque los semáforos no tienen ninguna noción de propiedad. Son contadores bastante sincronizados que tienen subprocesos de espera si el contador es 0. – Lucero

3

Basado en:

ManualResetEvent permite hilos para comunicarse entre sí por señalización. Normalmente, esta comunicación se refiere a una tarea que debe completar un subproceso antes de que puedan continuar otros subprocesos .

desde aquí:

http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx

que posiblemente desea mirar las barreras en el paquete de concurrencia de Java - específicamente CyclicBarrier creo:

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

Bloquea un número fijo de hilos hasta que se haya producido un evento en particular. Todos los hilos deben unirse en un punto de barrera.

+0

puede dar algunos ejemplos de esa barrera? No obtuve el ejemplo de la documentación. –

+0

Oh, he encontrado un artículo: http://tutorials.jenkov.com/java-util-concurrent/cyclicbarrier.html Por lo tanto, bloquea hasta que todos los hilos lleguen a la barrera (por lo que se forma la masa crítica) y luego continuará Bastante isntersting. Ahora sabré esto. Desafortunadamente, no es tan útil como pregunta, pero es que cada Objeto Java ha esperado, es ManualResetEvent –

+0

@BogdanMart Pero se vuelve a bloquear automáticamente, lo que significa que no es ni 'ManualResetEvent' ni' AutoResetEvent'. –

8

Pruebe CountDownLatch con el recuento de uno.

CountDownLatch startSignal = new CountDownLatch(1); 
+6

El problema con CountDownLatch es que no es reutilizable. Una vez que el seguro alcanza 0, ya no se puede usar. Se puede reemplazar con una nueva instancia de retención, pero esto puede crear condiciones de carrera a menos que se haga correctamente. – ripper234

2

creo que el quid de la ERM es .NET afinidad hilo y su capacidad para permitir que todos los hilos esperando pasar cuando se llama Set. Encontré que el uso del Semáforo funciona bien. Sin embargo, si tengo 10 o 15 hilos esperando, entonces me encuentro con otro problema. Específicamente, ocurre cuando se llama a Set. En .Net, se lanzan todos los hilos en espera. Usar un semphore no libera todo. Así que lo envolví en una clase. NOTA: Estoy muy familiarizado con el enhebrado .NET. Soy relativamente nuevo en el enhebrado y la sincronización de Java. Sin embargo, estoy dispuesto a saltar y obtener algunos comentarios reales. Aquí está mi aplicación con la hipótesis de que un principiante de Java haría:

public class ManualEvent { 
private final static int MAX_WAIT = 1000; 
private final static String TAG = "ManualEvent"; 
private Semaphore semaphore = new Semaphore(MAX_WAIT, false); 

private volatile boolean signaled = false; 
public ManualEvent(boolean signaled) { 
    this.signaled = signaled; 
    if (!signaled) { 
     semaphore.drainPermits(); 
    } 
} 

public boolean WaitOne() { 
    return WaitOne(Long.MAX_VALUE); 
} 

private volatile int count = 0; 
public boolean WaitOne(long millis) { 
    boolean bRc = true; 
    if (signaled) 
     return true; 

    try { 
     ++count; 
     if (count > MAX_WAIT) { 
      Log.w(TAG, "More requests than waits: " + String.valueOf(count)); 
     } 

     Log.d(TAG, "ManualEvent WaitOne Entered"); 
     bRc = semaphore.tryAcquire(millis, TimeUnit.MILLISECONDS); 
     Log.d(TAG, "ManualEvent WaitOne=" + String.valueOf(bRc)); 
    } 
    catch (InterruptedException e) { 
     bRc = false; 
    } 
    finally { 
     --count; 
    } 

    Log.d(TAG, "ManualEvent WaitOne Exit"); 
    return bRc; 
} 

public void Set() { 
    Log.d(TAG, "ManualEvent Set"); 
    signaled = true; 
    semaphore.release(MAX_WAIT); 
} 

public void Reset() { 
    signaled = false; 
    //stop any new requests 
    int count = semaphore.drainPermits(); 
    Log.d(TAG, "ManualEvent Reset: Permits drained=" + String.valueOf(count)); 
} 

}

También tenga en cuenta que estoy básicamente apostando a que no hay más de 1000 solicitudes en espera para un lanzamiento en un momento dado.Al liberar y adquirir en lotes, estoy intentando liberar cualquier hilo de espera. Tenga en cuenta que la llamada a WaitOne está trabajando 1 permiso a la vez.

23
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 boolean waitOne(long milliseconds) throws InterruptedException { 
    synchronized (monitor) { 
     if (open) 
     return true; 
     monitor.wait(milliseconds); 
     return open; 
    } 
    } 

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

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

Parece que no funcionará en absoluto: el hilo uno llama a 'waitOne()' y bloquea en 'monitor.wait()'. Enhebrar dos llamadas 'set' y bloques en' synchronized (monitor) '. Este es el único caso de uso, ¿verdad? Creo que está bien si simplemente dejas fuera la declaración 'synchronized' en' set'. –

+3

@LimitedAtonement: en Java debe estar en un bloque sincronizado para esperar en un objeto. Durante la espera, se libera el bloqueo del monitor de ese objeto, por lo que puede adquirirse en otro hilo. Ver http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html –

+0

@WayneUroda Mi mal. Supongo que no debería preguntarte por qué uno tiene que estar en un bloque 'sincronizado' para luego liberar el bloqueo llamando' wait'. Estoy seguro de que es tan viejo como las colinas;). –

Cuestiones relacionadas