28 January 2013

Purpose of wait(), notify() and notifyAll() methods defined in Object class of Java?


Java concurrency model uses locks to implement mutually exclusive access to objects in multi threaded environment.Locks are associated with every object in java(of type Object).

wait() notify() and notifyAll() methods are used by threads to communicate with each other while trying to access common object.

For example: suppose there is a 'telephone' object, which at one point of time can be used by only one thread. Like every other object in Java, 'telephone' object would also have an intrinsic lock (monitor) associated with it which at one point of time can be acquired by only one thread.  When a thead want to acquire a lock on telephone object it checks the status of lock and if it is already aquired by other thread then it will call wait() to move this thread to wait-set of telephone object. When other thread finishes the job it either calls notify() or notifyAll() method.
notify() will enable waiting thread in wait-set to aquire the lock and notifyAll() will notify all waiting threads and any thread with high priority will take over the lock on the telephone object.
----------------------------------------------------------------------------------
Another reason for using wait() notify() and notifyAll() methods:
----------------------------------------------------------------------------------
Threads also provide a secondary benefit: they do away with polling. Polling is usually implemented by a loop that is used to check some condition repeatedly. Once the condition is true, appropriate action is taken. This wastes CPU time. For example, consider the classic queuing problem, where one thread is producing some data and another is consuming it. To make the problem more interesting, suppose that the producer has to wait until the consumer is finished before it generates more data. In a polling system, the consumer would waste many CPU cycles while it waited for the producer to produce. Once the producer was finished, it would start polling, wasting more CPU cycles waiting for the consumer to finish, and so on. Clearly, this situation is undesirable.
To avoid polling, Java includes an elegant interrocess communication mechanism via the wait( ), notify( ), and notifyAll( ) methods. These methods are implemented as final methods in Object, so all classes have them. All three methods can be called only from within a synchronized method. Although conceptually advanced from a computer science perspective, the rules for using these methods are actually quite simple:
wait( ) tells the calling thread to give up the monitor and go to sleep until some other 
thread enters the same monitor and calls notify( ). 
notify( ) wakes up the first thread that called wait( ) on the same object. 
notifyAll( ) wakes up all the threads that called wait( ) on the same object. The 
highest priority thread will run first. 
These methods are declared within Object, as shown here:
final void wait( ) throws InterruptedException 
final void notify( ) 
final void notifyAll( )

A multi threaded program simulating producer consumer problem by only using synchronized method is as below( without using wait() notify() which will result in erroneous data:

//incorrect way of implementing producer and consumer problem
class Data { 
int n; 
synchronized int get() { 
System.out.println("Got: " + n); 
return n; 

synchronized void put(int n) { 
this.n = n; 
System.out.println("Put: " + n); 

}
class Producer implements Runnable { 
Data d; 
Producer(Data d) { 
this.d = d; 
new Thread(this, "Producer").start(); 

public void run() { 
int i = 0; 
while(true) { 
d.put(i++); 


}
class Consumer implements Runnable { 
Data d; 
Consumer(Data d) { 
this.d = d; 
new Thread(this, "Consumer").start(); 

public void run() { 
while(true) { 
d.get(); 


}
class ProducerConsumer { 
public static void main(String args[]) { 
Data d = new Data(); 
new Producer(d); 
new Consumer(d); 
System.out.println("Press Control-C to stop."); 

}
Output is as below:
Put: 1
Put: 2
Put: 3
Got: 3
Got: 3
Got: 3
The proper way to write this program in Java is to use wait( ) and notify( ) to signal in both directions, as shown here:

// A correct implementation of a producer and consumer. 
class Data1 { 
int n; 
boolean valueSet = false; 
synchronized int get() { 
if(!valueSet) 
try { 
wait(); 
} catch(InterruptedException e) { 
System.out.println("InterruptedException caught"); 

System.out.println("Got: " + n); 
valueSet = false; 
notify(); 
return n; 

synchronized void put(int n) { 
if(valueSet) 
try { 
wait(); 
} catch(InterruptedException e) { 
System.out.println("InterruptedException caught"); 

this.n = n; 
valueSet = true; 
System.out.println("Put: " + n); 
notify(); 

}
class Producer1 implements Runnable { 
Data1 d; 
Producer1(Data1 d) { 
this.d = d; 
new Thread(this, "Producer1").start(); 

public void run() { 
int i = 0; 
while(true) { 
d.put(i++); 


}
class Consumer1 implements Runnable { 
Data1 d; 
Consumer1(Data1 d) { 
this.d = d; 
new Thread(this, "Consumer1").start(); 

public void run() { 
while(true) { 
d.get(); 


}
class ProducerConsumerFixed { 
public static void main(String args[]) { 
Data1 d = new Data1(); 
new Producer1(d); 
new Consumer1(d); 
System.out.println("Press Control-C to stop."); 

}
Output:
Put: 299203
Got: 299203
Put: 299204
Got: 299204
Put: 299205
Got: 299205
Put: 299206
Got: 299206
Put: 299207
Got: 299207

No comments:

Post a Comment