Waiting for notification of events: using wait, notify, and notifyAll

If interdependent threads share data that’s processed alternately by them, the threads should be able to communicate with each other to notify when there’s a completion of events, or else the threads might not work correctly.

Imagine you’re waiting for your friend to go river rafting at a camp. You check whether she has arrived by peeping out of your tent every minute. This can become quite inconvenient. How about asking her to notify you when she arrives? Let’s implement this in code using the wait and notify methods from class Object. Because these methods are defined in class Object, they can be called on any Java object. Methods wait(), notify(), and notifyAll() enable threads sharing the same data to communicate with each other.

Methods wait(), notify(), and notifyAll() are defined in class Object and not in class Thread.

To call wait() or notify() a thread must own the object’s monitor lock. So calls to these methods should be placed within synchronized methods or blocks. Here’s an implementation of the previous example in code:

Methods wait(), notify(), and notifyAll() must be called from a synchronized method or code blocks or else an IllegalMonitor- StateException will be thrown by the JVM.

All overloaded versions of wait() throw a checked InterruptedException. Methods notify() and notifyAll() don’t throw an InterruptedException.

Unlike the Thread’s method join(), which waits for another thread to complete its execution, methods wait() and notify() don’t require a thread to complete their execution. The thread that calls wait(), waits for another thread to notify it using method notify() or notifyAll(). Some other examples from daily life of using wait() and notify() are teachers and students waiting to be notified for a next workshop on life skills (which can happen multiple times), an operator who answers a phone whenever she’s notified of an incoming call, or customers waiting for notification of new offers on a range of televisions.

Change in thread’s status when methods are executed from class Thread (sleep(), join(), yield()) and class Object (wait(), notify(), notifyAll())

Multiple threads might deadlock when they have acquired a lock on objects and are waiting to acquire locks on additional objects that are owned by other waiting threads. Let’s discuss this threading issue in detail next.

Code Snippet :

1)

package com.gs.corejava.collections;
class GoRafting extends Thread {
Friend friend;
/**
* @param friend
*/
public GoRafting(Friend friend) {
super();
this.friend = friend;
}
public void run() {
System.out.println("Friend reached " + friend.reached);
synchronized (friend) {
try {
friend.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Friend reached " + friend.reached);
}
}
class Friend extends Thread {
boolean reached = false;
public void run() {
while (!reached) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
confirmReached();
}
}
private synchronized void confirmReached() {
reached = true;
notify();
}
}
public class Camping {
public static void main(String[] args) {
Friend mohit = new Friend();
GoRafting goRafting = new GoRafting(mohit);
goRafting.start();
mohit.start();
}
}
Friend reached false
Friend reached true

2) if Notify is called from non-synchronized method :

private void confirmReached() {
reached = true;
notify();
}

Examples:

//-------------Wait Notify Example-------
//---Ex:1---
package com.gs.corejava.datastructures;
class Pen {
}
class Studentt extends Thread {
Pen pen;
public Studentt(Pen pen) {
this.pen = pen;
}
@Override
public void run() {
System.out.println(String.format("%s Doing some work with pen ",
this.getName()));
System.out.println(String.format("%s Going to wait for pen ",
this.getName()));
pen.notify();
try {
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("%s Wait over again using pen",
this.getName()));
}
}
public class WaitNotifyExample1 {
public static void main(String[] args) {
Pen pen = new Pen();
Thread st1 = new Thread(new Studentt(pen));
Thread st2 = new Thread(new Studentt(pen));
st1.start();
st2.start();
}
}
//--------------
Thread-2 Doing some work with pen
Thread-0 Doing some work with pen
Thread-2 Going to wait for pen
Thread-0 Going to wait for pen
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.gs.corejava.datastructures.Studentt.run(WaitNotifyExample1.java:20)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.gs.corejava.datastructures.Studentt.run(WaitNotifyExample1.java:20)
at java.lang.Thread.run(Thread.java:619)
//----------------
//---Ex:2---
pen.notify();
synchronized (pen) {
try {
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//--------------
Thread-2 Doing some work with pen
Thread-0 Doing some work with pen
Thread-2 Going to wait for pen
Thread-0 Going to wait for pen
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.gs.corejava.datastructures.Studentt.run(WaitNotifyExample1.java:20)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.gs.corejava.datastructures.Studentt.run(WaitNotifyExample1.java:20)
at java.lang.Thread.run(Thread.java:619)
//-------------
//---Ex:3---
synchronized (pen) {
try {
pen.notify();
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//------------
Thread-0 Doing some work with pen
Thread-2 Doing some work with pen
Thread-0 Going to wait for pen
Thread-2 Going to wait for pen
Thread-0 Wait over again using pen
Infinite Waiting for Thread-2 as no onw to wake up
//------------
//---Ex:4---
package com.gs.corejava.datastructures;
class Pen {
}
class Studentt extends Thread {
Pen pen;
public Studentt(Pen pen) {
this.pen = pen;
}
@Override
public void run() {
System.out.println(String.format("%s Doing some work with pen ",
this.getName()));
System.out.println(String.format("%s Going to wait for pen ",
this.getName()));
synchronized (pen) {
try {
pen.notify();
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(String.format("%s Wait over again using pen",
this.getName()));
}
}
public class WaitNotifyExample1 {
public static void main(String[] args) {
Pen pen = new Pen();
Thread st1 = new Thread(new Studentt(pen));
Thread st2 = new Thread(new Studentt(pen));
st1.start();
st2.start();
pen.notify();
}
}
//------------
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.gs.corejava.datastructures.WaitNotifyExample1.main(WaitNotifyExample1.java:40)
Thread-2 Doing some work with pen
Thread-0 Doing some work with pen
Thread-2 Going to wait for pen
Thread-0 Going to wait for pen
Thread-2 Wait over again using pen
Infinite Waiting for Thread-0 as no onw to wake up
//---Ex:5---
package com.gs.corejava.datastructures;
class Pen {
}
class Studentt extends Thread {
Pen pen;
public Studentt(Pen pen) {
this.pen = pen;
}
@Override
public void run() {
System.out.println(String.format("%s Doing some work with pen ",
this.getName()));
System.out.println(String.format("%s Going to wait for pen ",
this.getName()));
synchronized (pen) {
try {
pen.notify();
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(String.format("%s Wait over again using pen",
this.getName()));
}
}
public class WaitNotifyExample1 {
public static void main(String[] args) {
Pen pen = new Pen();
Thread st1 = new Thread(new Studentt(pen));
Thread st2 = new Thread(new Studentt(pen));
st1.start();
st2.start();
synchronized (pen) {
pen.notify();
}
}
}
//------------
Thread-2 Doing some work with pen
Thread-0 Doing some work with pen
Thread-2 Going to wait for pen
Thread-0 Going to wait for pen
Thread-2 Wait over again using pen
Infinite Waiting for Thread-0 as no onw to wake up
//------------
//---Ex:6---
package com.gs.corejava.datastructures;
class Pen {
}
class Studentt extends Thread {
Pen pen;
public Studentt(Pen pen) {
this.pen = pen;
}
@Override
public void run() {
System.out.println(String.format("%s Doing some work with pen ",
this.getName()));
System.out.println(String.format("%s Going to wait for pen ",
this.getName()));
synchronized (pen) {
try {
pen.notify();
pen.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(String.format("%s Wait over again using pen",
this.getName()));
}
}
public class WaitNotifyExample1 {
public static void main(String[] args) {
Pen pen = new Pen();
Thread st1 = new Thread(new Studentt(pen));
Thread st2 = new Thread(new Studentt(pen));
st1.start();
st2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (pen) {
pen.notify();
}
}
}
//------------
Thread-0 Doing some work with pen
Thread-2 Doing some work with pen
Thread-0 Going to wait for pen
Thread-2 Going to wait for pen
Thread-0 Wait over again using pen
Thread-2 Wait over again using pen
//------------

Producer And Consumer Problem :

package com.gs.corejava.datastructures;
class Book {
Integer integer = 0;
}
class thread1 extends Thread {
private Book book;
private Object obj1;
/**
* @param book
* @param obj1
* @param obj2
*/
public thread1(Book book, Object obj1) {
super();
this.book = book;
this.obj1 = obj1;
}
@Override
public void run() {
synchronized (obj1) {
while (book.integer % 2 == 0 && book.integer < 10) {
System.out.println("integer from "
+ Thread.currentThread().getName() + "::"
+ book.integer);
book.integer++;
try {
obj1.notify();
obj1.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class thread2 extends Thread {
private Book book;
private Object obj1;
/**
* @param book
* @param obj1
* @param obj2
*/
public thread2(Book book, Object obj1) {
super();
this.book = book;
this.obj1 = obj1;
}
@Override
public void run() {
synchronized (obj1) {
while (book.integer % 2 == 1 && book.integer < 10) {
System.out.println("integer from "
+ Thread.currentThread().getName() + "::"
+ book.integer);
book.integer++;
obj1.notify();
try {
obj1.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class ThreadOddEvenTest {
public static void main(String[] args) {
// Integer integer = new Integer(0);
Book book = new Book();
Object obj1 = new Object();
Thread thread1 = new thread1(book, obj1);
Thread thread2 = new thread2(book, obj1);
thread1.start();
thread2.start();
}
}
integer from Thread-0::0
integer from Thread-1::1
integer from Thread-0::2
integer from Thread-1::3
integer from Thread-0::4
integer from Thread-1::5
integer from Thread-0::6
integer from Thread-1::7
integer from Thread-0::8
integer from Thread-1::9