thread multi how example español create java multithreading events

multi - Esperando un evento en Java: ¿qué tan difícil es?



synchronized java (4)

Tengo un hilo que actualiza su estado de vez en cuando y quiero que un segundo hilo pueda esperar a que se realice el primer hilo. Algo como esto:

Thread 1: while(true) { ...do something... foo.notifyAll() ...wait for some condition that might never happen... ... } Thread 2: ... foo.wait(); ...

Ahora esto se ve bien y todo a menos que notifyAll () de Thread 1 se ejecute antes de la espera de Thread 2 (), en cuyo caso el Thread 2 espera hasta que el Thread 1 notifique nuevamente (lo que podría no suceder nunca).

Mis posibles soluciones:

a) Podría usar un CountDownLatch o un Future, pero ambos tienen el problema de que inherentemente solo se ejecutan una vez . Es decir, en el ciclo while de Thread 1, necesitaría crear un nuevo foo para esperar cada vez y el Thread 2 necesitaría preguntar a qué foo esperar. Tengo un mal presentimiento sobre simplemente escribir

while(true) { foo = new FutureTask(); ... foo.set(...); ...wait for a condition that might never be set... ... }

como me temo que en foo = new FutureTask (), ¿qué sucede cuando alguien esperaba el viejo foo (por "alguna razón", el conjunto no se llamaba, por ejemplo, un error en el manejo de excepciones)?

b) O podría usar un semáforo:

class Event { Semaphore sem; Event() { sem = new Semaphore(1); sem . } void signal() { sem.release(); } void reset() { sem.acquire(1); } void wait() { if (sem.tryAcquire(1)) { sem.release(); } } }

Pero me temo que hay alguna condición de carrera, si hay varios hilos esperando (it) mientras que otra señal (s) y reset () s.

Pregunta:

¿No hay nada en la API de Java que se asemeje al comportamiento de eventos de Windows? O, si desprecia Windows, algo así como el WaitGroup de golang (es decir, un CountDownLatch que permite countUp ())? ¿Cualquier cosa?

Cómo hacerlo manualmente:

El subproceso 2 no puede simplemente esperar debido a la activación espuria y en Java no hay forma de saber por qué Object.wait () regresó. Entonces necesito una variable de condición que almacene si el evento está señalado o no. Tema 2:

synchronized(foo) { while(!condition) { foo.wait(); } }

Y el hilo 1 por supuesto establece la condición en verdadero en un bloque sincronizado. ¡Gracias a weekens por la pista!

¿Hay una clase existente que envuelva ese comportamiento?

¿O necesito copiar y pegar todo el código?


Es una práctica estándar cambiar algún estado al realizar notifyAll y verificar algún estado al ejecutar wait ().

p.ej

boolean ready = false; // thread 1 synchronized(lock) { ready = true; lock.notifyAll(); } // thread 2 synchronized(lock) { while(!ready) lock.wait(); }

Con este enfoque, no importa si el hilo 1 o el hilo 2 adquieren primero el bloqueo.

Algunas herramientas de análisis de codificación le darán una advertencia si usa notificar o esperar sin establecer un valor o verificar un valor.


La forma más simple es solo decir

firstThread.join();

Esto se bloqueará hasta que finalice el primer subproceso.

Pero puede implementar el mismo usando wait / notify. Lamentablemente, no ha publicado los fragmentos de código reales, pero supongo que si la espera no finaliza cuando llama, notifique que sucede porque no colocó los dos en el bloque synchronized . Preste atención a que el "argumento" del bloque synchronized debe ser el mismo para el par de espera / notificación.


Puede usar wait () con tiempo de espera, en cuyo caso no correrá el riesgo de esperar para siempre. También tenga en cuenta que wait () puede regresar incluso si no hubo notificación () en absoluto, por lo tanto, deberá ajustar su espera dentro de algún ciclo condicionado. Esa es la forma estándar de esperar en Java.

synchronized(syncObject) { while(condition.isTrue()) { syncObject.wait(WAIT_TIMEOUT); } }

(en tu Subproceso 2)

Editar: se movió sincronizado fuera del ciclo.


Yo usaría una BlockingQueue entre los dos hilos. Usar wait y notify es así hace 5 minutos;)

enum Event { Event, Stop; } BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>(); // Thread 1 try { while(true) { ...do something... queue.put(Event.Event); ...wait for some condition that might never happen... ... } } finally { // Tell other thread we''ve finished. queue.put(Event.Stop}; } // Thread 2 ... switch ( queue.take() ) { case Event: ... break; default: ... break; }