Monday, June 19, 2017

Why wait(), notify() and notifyAll)() had to be on Object class than Thread

Reason: Reduce code-complexity and to avoid lot of additional lines of code.

Here is why:
Here is the producer-consumer problem that uses wait notify and notifyAll on Object Class:


Queue:
public class Queue {

private List numberQueue;
private final int MAX_SIZE = 5;
private int top = 0;
public void produce(Integer number) throws InterruptedException{
synchronized(numberQueue){
if(numberQueue.size() == MAX_SIZE)
numberQueue.wait();

numberQueue.add(number);
top =  top+1;
numberQueue.notifyAll();

}

}

public void consume() throws InterruptedException{
synchronized(numberQueue) {
if(numberQueue.size() == 0)
numberQueue.wait();

numberQueue.remove(top);
top = top-1;
numberQueue.notifyAll();

}
}


}



Producer:
public class Producer extends Thread{

Queue queue;

Producer(Queue queue){
this.queue = queue;
}

public void run(){

while(true){
Integer i = new java.util.Random().nextInt(50)+1;
try {
queue.produce(i);
} catch (InterruptedException e) {

e.printStackTrace();
}
}

}
}


Consumer:

public class Consumer extends Thread{

Queue queue;

Consumer(Queue queue){
this.queue = queue;

}

public void run(){

while(true){
try {
queue.consume();
} catch (InterruptedException e) {

e.printStackTrace();
}
}
}


}


ProdConsDemo:
public class ProdConsDemo {

public static void main(String[] args) {
Queue queue = new Queue();
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);

producer.start();
consumer.start();

}

}


I am not going to explain whats the program is all about since its pretty popular but what I am going to do is...Re-write the program considering wait, notify and notifyAll on Thread class.

Producer, Consumer and ProdConsDemo wont have to change since they dont have the wait/notifyAll methods. But below is the Queue class that gets changed with the highlighted lines of code.

Queue:

import java.util.List;
public class Queue {

private List numberQueue;
private final int MAX_SIZE = 5;
private int top = 0;
public void produce(Integer number) throws InterruptedException{
synchronized(numberQueue){

if(Thread.currentThread().getName() == "Producer" && numberQueue.size() == MAX_SIZE)
Thread.currentThread().wait();


numberQueue.add(number);
top =  top+1;
numberQueue.notifyAll();

}

}

public void consume() throws InterruptedException{
synchronized(numberQueue) {

if(Thread.currentThread().getName() == "Consumer" && numberQueue.size() == 0)
Thread.currentThread().wait();


numberQueue.remove(top);
top = top-1;
numberQueue.notifyAll();

}
}


}

The statement - Thread.currentThread().getName() is repetitive.


How to define the Shareable-Class:
Normally, the code inside the shared object is independent of the threads sharing it. And also, any critical section of the Shareable-class normally has a same/generalized business-logic across multiple threads. The logic won't vary from thread to thread.

Hence, in any critical section(a synchronized block or method), JVM needs the following 2 things to put the threads in wait or active state based on the locks.
1) Which is the currently running thread.
2) Which is the object on which the currently running thread acquired the monitor.

It is evident from the critical section that both the information can clearly be inferred by JVM. Then JVM will act as soon as it encounters the wait() irrespective of which class(Object or Thread) callling wait() or notify/notifyAll() methods.

No comments:

How J2EE components work together in any Container - Spring or Application Server

In a Spring+Jersey+Hibernate RESTful webapplication, we can spot various J2EE components - JTA, JPA, Java Bean Validation, JSON-B API for B...