I just made one producer and one consumer thread. When list is empty consumer went to waiting state, then producer insert an item in list and calls notify()
to invoke consumer thread but consumer is not invoking. It remains in waiting state.
Code that I have tried is:
package xs;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class TestMain {
public static void main(String[] args) {
product pro = new product();
producer produce = new producer(pro);
consumer consume = new consumer(pro);
Thread thr1 = new Thread(produce, "Producer");
Thread thr2 = new Thread(consume, "consumer");
thr1.start();
thr2.start();
}
}
class product{
List<Date> list;
public product() {
list = new ArrayList<Date>();
}
public void produce(Date i){
list.add(i);
}
public Date consume(){
return list.remove(0);
}
}
class producer implements Runnable{
product product;
@Override
public void run() {
while(true){
synchronized (this) {
while(product.list.size() == 2){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
product.produce(new Date());
System.out.println("Produced "+product.list.size());
notify();
}
}
}
public producer(product product) {
this.product = product;
}
}
class consumer implements Runnable{
product product;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
synchronized (this) {
notify();
while(product.list.size() == 0){
try {
System.out.println("Going to wait..."+ product.list.size());
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("consumed"+ product.consume());
}
}
}
public consumer(product product) {
this.product = product;
}
}
Output it's giving:
Going to wait...0
Produced 1
Produced 2
As you can see consumer is not coming in action after wait()
call.
Your producer and consumer are each synchronizing, waiting and notifying their own monitor. You need to give them a shared monitor to use for synchronization etc.
For example:
Object monitor = new Object();
product pro = new product();
producer produce = new producer(monitor, pro);
consumer consume = new consumer(monitor, pro);
Change both the producer
and consumer
constructors to accept another parameter (of type Object
) and save it in a field, then change synchronized(this)
to synchronized(monitor)
, wait()
to monitor.wait()
and notify()
to monitor.notify()
and all will be well.
(You could just use product
to synchronize on, but personally I prefer to use an object which is only used for synchronization, or an object of a thread-centric class designed specifically for this.)
Also, note that your code feels very un-Java-like due to your class names, which should be Product
, Producer
and Consumer
to follow normal Java naming conventions.
See more on this question at Stackoverflow