sincronizacion resueltos metodo hilos esperas entre ejemplos ejemplo diferencias java multithreading wait notify

java - resueltos - ¿Cómo pueden llamarse los métodos wait() y notify() a objetos que no son hilos?



wait y notify java ejemplo (7)

¿Cómo se pueden notify() métodos wait() y notify() en Objetos que no son Threads? Eso realmente no tiene sentido, ¿verdad?

Sin duda, debe tener sentido, sin embargo, porque los dos métodos están disponibles para todos los objetos de Java. ¿Alguien puede dar una explicación? Tengo problemas para entender cómo comunicarme entre hilos usando wait() y notify() .


"Este método solo debe ser llamado por un hilo que sea el propietario del monitor de este objeto". Así que creo que debes asegurarte de que haya un hilo que sea el monitor del objeto.


Cuando pones un código dentro del bloque sincronizado:

sychronized(lock){...}

un hilo que desea realizar lo que está dentro de este bloque primero adquiere un bloqueo en un objeto y solo un hilo a la vez puede ejecutar el código bloqueado en el mismo objeto. Cualquier objeto se puede usar como un bloqueo, pero debe tener cuidado de elegir el objeto relevante para el alcance. Por ejemplo, cuando tiene varios hilos que agregan algo a la cuenta y todos tienen algún código responsable de eso dentro de un bloque como:

sychronized(this){...}

entonces no tiene lugar ninguna sincronización porque todos se bloquearon en un objeto diferente. En su lugar, debe usar un objeto de cuenta como el bloqueo. Ahora considere que estos hilos también tienen un método para retirar de una cuenta. En este caso, puede ocurrir una situación en la que un hilo que desee retirar algo encuentre una cuenta vacía. Debería esperar hasta que haya algo de dinero y liberar el bloqueo a otros hilos para evitar un punto muerto. Para eso sirven los métodos de esperar y notificar. En este ejemplo, un hilo que encuentra una cuenta vacía libera el bloqueo y espera la señal de algún hilo que realiza el depósito:

while(balance < amountToWithdraw){ lock.wait(); }

Cuando otro hilo deposita algo de dinero, señala otros hilos esperando en el mismo bloqueo. (por supuesto, el código responsable de realizar depósitos y retiros debe estar sincronizado en el mismo bloqueo para que esto funcione y para evitar la corrupción de datos).

balance += amountToDeposit; lock.signallAll;

Como ve, los métodos de espera y notificación solo tienen sentido dentro de bloques o métodos sincronizados.


En Java, todos los Objetos implementan estos dos métodos, obviamente, si no hay un monitor, esos dos métodos son inútiles.


Puede detener el hilo por el tiempo que desee utilizando el método estático Thread class sleep() .

public class Main { //some code here //Thre thread will sleep for 5sec. Thread.sleep(5000); }

Si desea detener algunos objetos, necesita llamar a este método dentro de bloques syncronized .

public class Main { //some code public void waitObject(Object object) throws InterruptedException { synchronized(object) { object.wait(); } } public void notifyObject(Object object) throws InterruptedException { synchronized(object) { object.notify(); } }

}

PD. Sory si entiendo mal tu pregunta (el inglés no es mi lengua materna)


Puede usar wait() y notify() para sincronizar su lógica. Como ejemplo

synchronized (lock) { lock.wait(); // Will block until lock.notify() is called on another thread. } // Somewhere else... ... synchronized (lock) { lock.notify(); // Will wake up lock.wait() }

con lock siendo el miembro de la clase Object lock = new Object();


Los bloqueos son diferentes de los hilos. El bloqueo está en la estructura de datos que está siendo protegida. Los hilos son las cosas que acceden a la estructura de datos. Los bloqueos están en el objeto de estructura de datos para evitar que los subprocesos accedan a la estructura de datos de una manera insegura.

Cualquier objeto se puede usar como un bloqueo intrínseco (es decir, se usa junto con synchronized ). De esta forma, puede proteger el acceso a cualquier objeto agregando el modificador sincronizado a los métodos que acceden a los datos compartidos. (No es una buena idea, porque permite que cualquier subproceso que pueda acceder al objeto adquiera su bloqueo, incluso si no está llamando a ningún método, es mejor mantener el bloqueo como un miembro privado de la estructura de datos bloqueada, para que el acceso sea limitado.)

wait y notify se llaman a los objetos que se utilizan como bloqueos. El bloqueo es un punto de comunicación compartido:

  • Cuando un hilo que tiene un candado llama a notifyAll , los otros hilos que esperan en ese mismo candado reciben una notificación. Cuando un hilo que tiene un bloqueo llama a notify , uno de los hilos esperando en ese mismo bloqueo es notificado.

  • Cuando un hilo que tiene llamadas de bloqueo wait , el hilo libera el bloqueo y permanece inactivo hasta que a) recibe una notificación, o b) simplemente se despierta arbitrariamente (el "despertador espurio"); el hilo de espera permanece atascado en la llamada para esperar hasta que se despierte debido a una de estas 2 razones, luego el hilo debe volver a adquirir el bloqueo antes de que pueda salir del método de espera.

Consulte el tutorial de Oracle sobre bloques protegidos , la clase Drop es la estructura de datos compartidos, los hilos que utilizan ejecutables Producer y Consumer están accediendo a ella. Bloquear en el objeto Drop controla cómo los hilos acceden a los datos del objeto Drop.

Los subprocesos se usan como bloqueos en la implementación de JVM. Se recomienda a los desarrolladores de aplicaciones evitar el uso de subprocesos como bloqueos. Por ejemplo, la documentación para Thread.join dice:

Esta implementación usa un ciclo de esto. Llamadas esperadas condicionadas en this.isAlive. Cuando un hilo termina el método this.notifyAll se invoca. Se recomienda que las aplicaciones no usen esperar, notificar ni notificar todas las instancias de subprocesos.


  1. Esperar y notificar no son solo métodos normales o utilidad de sincronización, más que eso son un mecanismo de comunicación entre dos hilos en Java. Y la clase Object es el lugar correcto para que estén disponibles para cada objeto si este mecanismo no está disponible a través de ninguna palabra clave java como synchronized. Recuerde sincronizar y esperar notificar son dos áreas diferentes y no confundir que son iguales o relacionadas. Sincronizado es proporcionar exclusión mutua y garantizar la seguridad de subprocesos de la clase de Java como condición de carrera, mientras que esperar y notificar son mecanismos de comunicación entre dos subprocesos.
  2. Los bloqueos están disponibles por base de Objeto, que es otra razón por la que se espera y se notifica en clase de objeto en lugar de clase de subproceso.
  3. En Java para ingresar una sección crítica del código, Threads necesita bloquearse y esperan el bloqueo, no saben qué hilos mantienen bloqueados, simplemente saben que el bloqueo se retiene por algún hilo y deben esperar al bloqueo en lugar de saber qué el hilo está dentro del bloque sincronizado y les pide que suelten el bloqueo. esta analogía se ajusta a esperar y notificar estar en clase de objeto en lugar de hilo en Java.

Analogía: un hilo de Java es un usuario y el inodoro es un bloque de código que el hilo desea ejecutar. Java proporciona una forma de bloquear el código para un hilo que se está ejecutando actualmente utilizando el keywokd sincronizado, y hacer que otros hilos que deseen usarlo esperen hasta que termine el primer hilo. Estos otros hilos se colocan en el estado de espera. Java NO ES TAN FÁCIL como la estación de servicio porque no hay cola para hilos en espera. Cualquiera de los hilos de espera puede obtener el monitor siguiente, independientemente del orden que lo pidieron. La única garantía es que todos los hilos llegarán a utilizar el código supervisado tarde o temprano.

Fuente

Si observa el siguiente código de productor y consumidor:
sharedQueue objeto sharedQueue actúa en la comunicación entre subprocesos entre subprocesos de producer and consumer .

import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class ProducerConsumerSolution { public static void main(String args[]) { Vector<Integer> sharedQueue = new Vector<Integer>(); int size = 4; Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer"); Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer"); prodThread.start(); consThread.start(); } } class Producer implements Runnable { private final Vector<Integer> sharedQueue; private final int SIZE; public Producer(Vector<Integer> sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { for (int i = 0; i < 7; i++) { System.out.println("Produced: " + i); try { produce(i); } catch (InterruptedException ex) { Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex); } } } private void produce(int i) throws InterruptedException { // wait if queue is full while (sharedQueue.size() == SIZE) { synchronized (sharedQueue) { System.out.println("Queue is full " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } // producing element and notify consumers synchronized (sharedQueue) { sharedQueue.add(i); sharedQueue.notifyAll(); } } } class Consumer implements Runnable { private final Vector<Integer> sharedQueue; private final int SIZE; public Consumer(Vector<Integer> sharedQueue, int size) { this.sharedQueue = sharedQueue; this.SIZE = size; } @Override public void run() { while (true) { try { System.out.println("Consumed: " + consume()); Thread.sleep(50); } catch (InterruptedException ex) { Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex); } } } private int consume() throws InterruptedException { //wait if queue is empty while (sharedQueue.isEmpty()) { synchronized (sharedQueue) { System.out.println("Queue is empty " + Thread.currentThread().getName() + " is waiting , size: " + sharedQueue.size()); sharedQueue.wait(); } } //Otherwise consume element and notify waiting producer synchronized (sharedQueue) { sharedQueue.notifyAll(); return (Integer) sharedQueue.remove(0); } } }

Fuente