El wait() y notificar() son métodos de la clase Object . Se les presentó para separarse del sondeo, que es el proceso de verificar repetidamente que se cumpla una condición. El sondeo desperdicia considerablemente los recursos de la CPU, por lo que no es el preferido.
método esperar()
El método wait() es parte de la clase java.lang.Object . Cuando se llama al método wait(), el subproceso de llamada detiene su ejecución hasta que algún otro subproceso invoque el método notificar() o notificar a todos().
El método wait() tiene 3 variaciones:
1. wait(): Esta es una versión básica del método wait() que no acepta ningún argumento. Hará que el subproceso espere hasta que se llame a la notificación.
public final void wait()
2. espera (tiempo de espera prolongado): esta versión del método wait() toma un único argumento de tiempo de espera. Hará que el subproceso espere hasta que se llame a la notificación o hasta que se agote el tiempo de espera (uno que ocurra antes).
public final void wait(long timeout)
3. espera (tiempo de espera largo, int nanosegundos): esta versión del método wait() toma un argumento de tiempo de espera, así como un argumento de nanosegundos para mayor precisión.
public final void wait(long timeout, int nanoseconds)
método de notificación()
El método de notificación() se define en la clase de objeto, que es la clase de nivel superior de Java. Se usa para activar solo un subproceso que está esperando un objeto, y ese subproceso luego comienza a ejecutarse. El método de notificación de clase de subproceso() se utiliza para activar un solo subproceso.
public final void notify()
Diferencias entre esperar() y notificar()
S. No. | Esperar() | notificar() |
---|---|---|
1. | Cuando se llama a wait() en un subproceso que mantiene el bloqueo del monitor, entrega el bloqueo del monitor y entra en el estado de espera. | Cuando se llama a notificar() en un subproceso que mantiene el bloqueo del monitor, simboliza que el subproceso pronto entregará el bloqueo. |
2. | Puede haber varios subprocesos en estado de espera a la vez. |
Uno de los subprocesos en espera se selecciona aleatoriamente y se notifica sobre el mismo. El subproceso notificado luego sale del estado de espera y entra en el estado bloqueado donde espera hasta que el subproceso anterior haya renunciado al bloqueo y este subproceso lo haya adquirido. Una vez que adquiere el bloqueo, ingresa al estado ejecutable donde espera el tiempo de la CPU y luego comienza a ejecutarse. |
3. | El método wait() está definido en la clase Object | El método de notificación() se define en la clase de objeto |
4. | El método wait() se utiliza para la comunicación entre subprocesos. | El método de notificación() se usa para despertar un solo hilo |
5. | El método wait() es parte de la clase java.lang.Object | El método de notificación() no tiene ningún valor de tipo de retorno |
6. | El método wait() está estrechamente integrado con el bloqueo de sincronización | El método de notificación() se usa para dar la notificación de un hilo para un objeto en particular |
A continuación se muestra una demostración del método wait() y notificar():
Java
// Java Program to demonstrate usage of wait() and notify() class demo { // variable to check if part1 has returned // volatile used to prevent threads from // storing local copies of variable volatile boolean part1done = false; // method synchronized on this // i.e. current object of demo synchronized void part1() { System.out.println("Welcome to India"); part1done = true; System.out.println( "Thread t1 about to surrender lock"); // notify the waiting thread, if any notify(); } // method synchronized on this // i.e. current object of demo synchronized void part2() { // loop to prevent spurious wake-up while (!part1done) { try { System.out.println("Thread t2 waiting"); // wait till notify is called wait(); System.out.println( "Thread t2 running again"); } catch (Exception e) { System.out.println(e.getClass()); } } System.out.println("Do visit Taj Mahal"); } } public class Main { public static void main(String[] args) { // Make an instance of demo class demo obj = new demo(); // Thread t1 will call part1() Thread t1 = new Thread(new Runnable() { public void run() { obj.part1(); } }); // Thread t2 will call part2() Thread t2 = new Thread(new Runnable() { public void run() { obj.part2(); } }); // Start t2 and then t1 t2.start(); t1.start(); } }
Thread t2 waiting Welcome to India Thread t1 about to surrender lock Thread t2 running again Do visit Taj Mahal
Varias excepciones:
1. esperar()
- Es obligatorio encerrar wait() en un bloque try-catch porque si un subproceso presente en el estado de espera se interrumpe, arrojará una InterruptedException.
- Las otras dos variaciones de los parámetros de alojamiento de espera generarán IllegalArgumentException si el valor del tiempo de espera es negativo o el valor de los nanosegundos no está en el rango de 0 a 9,99,999.
A continuación se muestra la implementación para el manejo de excepciones.
Java
// Program demonstrating occurrence of InterruptedException class demo { volatile boolean part1done = false; synchronized void part1() { System.out.println("Welcome to India"); part1done = true; // notify() has been commented, waiting // thread remains waiting forever notify(); } synchronized void part2() { while (!part1done) { try { wait(); } catch (Exception e) { System.out.println("Exception : " + e.getClass()); // quit program after exception is thrown System.exit(-1); } } System.out.println("Do visit Taj Mahal"); } } public class Main { public static void main(String[] args) { // Make an instance of demo class demo obj = new demo(); // Thread t1 will call part1() Thread t1 = new Thread(new Runnable() { public void run() { obj.part1(); } }); // Thread t2 will call part2() Thread t2 = new Thread(new Runnable() { public void run() { obj.part2(); } }); // Start t2 and then t1 t2.start(); t1.start(); // This is a counter which will // interrupt Thread t2 after 3 seconds long startTime = System.currentTimeMillis(); while (true) { if (System.currentTimeMillis() - startTime > 3000) t2.interrupt(); } } }
Welcome to India Exception : class java.lang.InterruptedException
2. notificar()
A diferencia de wait(), el método de notificación no arroja una excepción interrumpida, por lo que no es obligatorio alojarlo dentro de un bloque de prueba y captura.
Nota:
- wait() y notificar() tienen una tendencia a lanzar IllegalMonitorStateException
- Esto ocurre cuando un subproceso retiene el bloqueo del monitor del objeto A e intenta llamar a esperar o notificar en el objeto B.
- En todos los ejemplos anteriores, los métodos se sincronizaron en «esto», es decir, el objeto utilizado para llamar a esos métodos (obj). Además, se llamaba a wait() y notificar() como this.wait() y this.notify() (el uso de esto era redundante). Por lo tanto, no hubo problema.
- En el siguiente ejemplo, los métodos part1 y part2 ahora están sincronizados en un objeto Integer, pero se sigue llamando a wait() y notificar() en el objeto que llamó a estos métodos (obj).
- Esto provoca una IllegalMonitorStateException
A continuación se muestra la implementación del manejo de excepciones.
Java
// Program to demonstrate IllegalMonitorStateException class demo { volatile boolean part1done = false; // Made an Integer object a // and set it randomly to 5 Integer a = 5; void part1() { // Synchronized code on a synchronized (a) { System.out.println("Welcome to India"); part1done = true; // calling this.notify() notify(); } } void part2() { // Synchronized code on a synchronized (a) { while (!part1done) { try { // calling this.wait() wait(); } catch (Exception e) { System.out.println("Exception: "+e.getClass()); System.exit(-1); } } System.out.println("Do visit Taj Mahal"); } } } public class Main { public static void main(String[] args) { // Make an instance of demo class demo obj = new demo(); // Thread t1 will call part1() Thread t1 = new Thread(new Runnable() { public void run() { obj.part1(); } }); // Thread t2 will call part2() Thread t2 = new Thread(new Runnable() { public void run() { obj.part2(); } }); // Start t2 and then t1 t2.start(); t1.start(); } }
Exception: class java.lang.IllegalMonitorStateException
Nota: Para corregir el código anterior, simplemente reemplace notificar() con a.notificar() en la línea 17 y esperar() con a.esperar() en la línea 29.