thread temporizador sincronizacion manejo hilos fuente entre ejemplos ejemplo diferencia con codigo java multithreading wait notify

temporizador - Java: ¿Cómo puede un hilo esperar en varios objetos?



temporizador en java con hilos (8)

Bloqueo en ambos casos sobre el mismo objeto. Llame en el caso a) o en el caso b) notifique () sobre el mismo objeto.

Un subproceso puede usar Object.wait() para bloquear hasta que otro subproceso llame a notify() o notifyAll() en ese objeto.

Pero, ¿qué pasa si un hilo quiere esperar hasta que se señaliza uno de los múltiples objetos? Por ejemplo, mi hilo debe esperar hasta que a) los bytes estén disponibles para leer desde un InputStream o b) un elemento se agregue a un ArrayList .

¿Cómo puede el hilo esperar a que ocurra alguno de estos eventos?

EDITAR

Esta pregunta se refiere a la espera de que se completen varios subprocesos; mi caso implica un subproceso que espera que uno de los muchos objetos se clasifique.


Para manejar la terminación de cualquier hilo de un conjunto dado sin esperar a que todos ellos finalicen , se puede usar un Objeto común dedicado ( lastExited abajo) como monitor ( wait() y notify() en bloques synchronized ). Se requieren monitores adicionales para garantizar que en cualquier momento, como máximo, un subproceso está saliendo ( notifyExitMutex ) y como máximo un subproceso está esperando a que salga cualquier subproceso ( waitAnyExitMonitor ); por lo tanto, los pares de wait() / notify() pertenecen siempre a bloques diferentes.

Ejemplo (todas las terminaciones de proceso se manejan en el orden en que terminaron los hilos ):

import java.util.Random; public class ThreadMonitor { private final Runnable[] lastExited = { null }; private final Object notifyExitMutex = new Object(); public void startThread(final Runnable runnable) { (new Thread(new Runnable() { public void run() { try { runnable.run(); } catch (Throwable t) { } synchronized (notifyExitMutex) { synchronized (lastExited) { while (true) { try { if (lastExited[0] != null) lastExited.wait(); lastExited[0] = runnable; lastExited.notify(); return; } catch (InterruptedException e) { } } } } }})).start(); } private final Object waitAnyExitMutex = new Object(); public Runnable waitAnyExit() throws InterruptedException { synchronized (waitAnyExitMutex) { synchronized (lastExited) { if (lastExited[0] == null) lastExited.wait(); Runnable runnable = lastExited[0]; lastExited[0] = null; lastExited.notify(); return runnable; } } } private static Random random = new Random(); public static void main(String[] args) throws InterruptedException { ThreadMonitor threadMonitor = new ThreadMonitor(); int threadCount = 0; while (threadCount != 100) { Runnable runnable = new Runnable() { public void run() { try { Thread.sleep(1000 + random.nextInt(100)); } catch (InterruptedException e) { } }}; threadMonitor.startThread(runnable); System.err.println(runnable + " started"); threadCount++; } while (threadCount != 0) { Runnable runnable = threadMonitor.waitAnyExit(); System.err.println(runnable + " exited"); threadCount--; } } }


Parece que en tu caso estás esperando "notificaciones" de dos fuentes diferentes. Es posible que no tenga que "esperar" (como en java synchronized(object) object.wait() normal synchronized(object) object.wait() ) en esos dos objetos per se, sino que ambos hablen a una cola o qué no (como mencionan las otras respuestas, algunos bloqueos colección como LinkedBlockingQueue).

Si realmente quiere "esperar" en dos objetos java diferentes, puede hacerlo aplicando algunos de los principios de esta respuesta: https://.com/a/31885029/32453 (básicamente un hilo nuevo) cada uno para hacer una espera en cada uno de los objetos que está esperando, pídales que notifiquen al subproceso principal cuando se notifique al objeto en sí), pero puede que no sea fácil administrar los aspectos sincronizados.


Poco tarde, pero es una pregunta muy interesante! Parece que puede esperar varias condiciones, con el mismo rendimiento y sin subprocesos adicionales; ¡Es solo una cuestión de definir el problema! Me tomé el tiempo para escribir una explicación más detallada dentro de las confirmaciones del código de abajo. A petición extraeré la abstracción:

Entonces, de hecho, esperar en múltiples objetos es lo mismo que esperar en múltiples condiciones. Pero el siguiente paso es fusionar sus condiciones secundarias en una condición de red, una condición única. Y cuando cualquier componente de la condición causaría que se hiciera realidad, volteas un booleano y notificas el bloqueo (como cualquier otra condición de notificación de espera).

Mi enfoque :

Para cualquier condición, solo puede dar como resultado dos valores (verdadero y falso). Cómo se produce ese valor es irrelevante. En su caso, su "condición funcional" es cuando uno de los dos valores es verdadero: (value_a || value_b). Yo llamo a esto "condición funcional" el "Punto Nexus". Si aplica la perspectiva de que cualquier condición compleja, sin importar cuán compleja sea, siempre produce un resultado simple (verdadero o falso), entonces lo que realmente está pidiendo es "¿Qué hará que mi condición neta se vuelva verdadera?" (Suponiendo que la lógica es "Espere hasta que sea verdadero"). Por lo tanto, cuando un subproceso hace que un componente de su condición se convierta en verdadero (estableciendo value_a, o value_b en verdadero, en su caso), y sabe que esto hará que se cumpla la condición deseada de "red", entonces puede simplificar su acercarse a un clásico (en el sentido de que gira una sola bandera booleana y libera un bloqueo). Con este concepto, puede aplicar un enfoque de ordenación de objetos para ayudar a mejorar la claridad de su lógica general:

import java.util.HashSet; import java.util.Set; /** * The concept is that all control flow operation converge * to a single value: true or false. In the case of N * components in which create the resulting value, the * theory is the same. So I believe this is a matter of * perspective and permitting ''simple complexity''. for example: * * given the statement: * while(condition_a || condition_b || ...) { ... } * * you could think of it as: * let C = the boolean -resulting- value of (condition_a || condition_b || ...), * so C = (condition_a || condition_b || ...); * * Now if we were to we-write the statement, in lamest-terms: * while(C) { ... } * * Now if you recognise this form, you''ll notice its just the standard * syntax for any control-flow statement? * * while(condition_is_not_met) { * synchronized (lock_for_condition) { * lock_for_condition.wait(); * } * } * * So in theory, even if the said condition was evolved from some * complex form, it should be treated as nothing more then if it * was in the simplest form. So whenever a component of the condition, * in which cause the net-condition (resulting value of the complex * condition) to be met, you would simply flip the boolean and notify * a lock to un-park whoever is waiting on it. Just like any standard * fashion. * * So thinking ahead, if you were to think of your given condition as a * function whos result is true or false, and takes the parameters of the states * in which its comprised of ( f(...) = (state_a || state_b && state_c), for example ) * then you would recognize "If I enter this state, in which this I know would * cause that condition/lock to become true, I should just flip the switch switch, * and notify". * * So in your example, your ''functional condition'' is: * while(!state_a && !state_b) { * wait until state a or state b is false .... * } * * So armed with this mindset, using a simple/assertive form, * you would recognize that the overall question: * -> What would cause my condition to be true? : if state_a is true OR state_b is true * Ok... So, that means: When state_a or state_b turn true, my overall condition is met! * So... I can just simplify this thing: * * boolean net_condition = ... * final Object lock = new Lock(); * * void await() { * synchronized(lock) { * while(!net_condition) { * lock.wait(); * } * } * } * * Almighty, so whenever I turn state_a true, I should just flip and notify * the net_condition! * * * * Now for a more expanded form of the SAME THING, just more direct and clear: * * @author Jamie Meisch */ public class Main { /** * * The equivalent if one was to "Wait for one of many condition/lock to * be notify me when met" : * * synchronized(lock_a,lock_b,lock_c) { * while(!condition_a || !condition_b || !condition_c) { * condition_a.wait(); * condition_b.wait(); * condition_c.wait(); * } * } * */ public static void main(String... args) { OrNexusLock lock = new OrNexusLock(); // The workers register themselves as their own variable as part of the overall condition, // in which is defined by the OrNuxusLock custom-implement. Which will be true if any of // the given variables are true SpinningWarrior warrior_a = new SpinningWarrior(lock,1000,5); SpinningWarrior warrior_b = new SpinningWarrior(lock,1000,20); SpinningWarrior warrior_c = new SpinningWarrior(lock,1000,50); new Thread(warrior_a).start(); new Thread(warrior_b).start(); new Thread(warrior_c).start(); // So... if any one of these guys reaches 1000, stop waiting: // ^ As defined by our implement within the OrNexusLock try { System.out.println("Waiting for one of these guys to be done, or two, or all! does not matter, whoever comes first"); lock.await(); System.out.println("WIN: " + warrior_a.value() + ":" + warrior_b.value() + ":" + warrior_c.value()); } catch (InterruptedException ignored) { } } // For those not using Java 8 :) public interface Condition { boolean value(); } /** * A variable in which the net locks ''condition function'' * uses to determine its overall -net- state. */ public static class Variable { private final Object lock; private final Condition con; private Variable(Object lock, Condition con) { this.lock = lock; this.con = con; } public boolean value() { return con.value(); } //When the value of the condition changes, this should be called public void valueChanged() { synchronized (lock) { lock.notifyAll(); } } } /** * * The lock has a custom function in which it derives its resulting * -overall- state (met, or not met). The form of the function does * not matter, but it only has boolean variables to work from. The * conditions are in their abstract form (a boolean value, how ever * that sub-condition is met). It''s important to retain the theory * that complex conditions yeild a simple result. So expressing a * complex statement such as ( field * 5 > 20 ) results in a simple * true or false value condition/variable is what this approach is * about. Also by centerializing the overal logic, its much more * clear then the raw -simplest- form (listed above), and just * as fast! */ public static abstract class NexusLock { private final Object lock; public NexusLock() { lock = new Object(); } //Any complex condition you can fathom! //Plus I prefer it be consolidated into a nexus point, // and not asserted by assertive wake-ups protected abstract boolean stateFunction(); protected Variable newVariable(Condition condition) { return new Variable(lock, condition); } //Wait for the overall condition to be met public void await() throws InterruptedException { synchronized (lock) { while (!stateFunction()) { lock.wait(); } } } } // A implement in which any variable must be true public static class OrNexusLock extends NexusLock { private final Set<Variable> vars = new HashSet<>(); public OrNexusLock() { } public Variable newVar(Condition con) { Variable var = newVariable(con); vars.add(var); //register it as a general component of or net condition // We should notify the thread since our functional-condition has changed/evolved: synchronized (lock) { lock.notifyAll(); } return var; } @Override public boolean stateFunction() { //Our condition for this lock // if any variable is true: if(var_a || var_b || var_c || ...) for(Variable var : vars) { if(var.value() == true) return true; } return false; } } //increments a value with delay, the condition is met when the provided count is reached private static class SpinningWarrior implements Runnable, Condition { private final int count; private final long delay; private final Variable var; private int tick = 0; public SpinningWarrior(OrNexusLock lock, int count, long delay) { this.var = lock.newVar(this); this.count = count; //What to count to? this.delay = delay; } @Override public void run() { while (state_value==false) { //We''re still counting up! tick++; chkState(); try { Thread.sleep(delay); } catch (InterruptedException ignored) { break; } } } /** * Though redundant value-change-notification are OK, * its best to prevent them. As such its made clear to * that we will ever change state once. */ private boolean state_value = false; private void chkState() { if(state_value ==true) return; if(tick >= count) { state_value = true; var.valueChanged(); //Our value has changed } } @Override public boolean value() { return state_value; //We could compute our condition in here, but for example sake. } } }


Puedes esperar solo en un monitor. Así que los notificadores deben notificar a este monitor. No hay otra manera en esta sincronización de bajo nivel.


Te encuentras en un mundo de dolor. Use una abstracción de nivel superior, como una cola de mensajes de bloqueo, desde la cual el hilo puede consumir mensajes como ''más bytes disponibles'' o ''elemento agregado''.


Todos podrían usar el mismo mutex. Su consumidor está esperando ese mutex, los otros dos notifican ese mutex cuando el primero puede continuar.


Un hilo no puede esperar en más de un objeto a la vez.

Los métodos de wait() y de notify() son específicos del objeto. El método wait() suspende el subproceso de ejecución actual e indica al objeto que realice un seguimiento del subproceso suspendido. El método notify() le dice al objeto que despierte los subprocesos suspendidos de los que actualmente está realizando un seguimiento.

Enlace útil: ¿Puede un hilo llamar a la espera () en dos bloqueos a la vez en Java (6)?