Reputation: 469
I am refreshing my memory about Java concurrency and I was playing around with the popular producer consumer problem. I have implemented the below code which works correctly if there is a single producer and a single consumer. However, It doesn't function correctly if there are multiple producers/consumers. I can't see why
public class ProducerConsumer {
static Monitor monitor;
public ProducerConsumer(int maxSize)
{
monitor = new Monitor(maxSize);
new Producer().start();
new Producer().start();
new Consumer().start();
new Consumer().start();
}
class Producer extends Thread{
@Override
public void run() {
while(true)
{
try {
monitor.insert();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread{
@Override
public void run() {
while(true)
{
try {
monitor.remove();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Monitor {
int n;
int maxSize;
public Monitor(int maxSize)
{
n=0;
this.maxSize = maxSize;
}
synchronized void insert() throws InterruptedException
{
if(n==maxSize)
wait();
System.out.println("Producer: "+n++);
if(n==1)
notifyAll();
}
synchronized void remove() throws InterruptedException
{
if(n==0)
wait();
System.out.println("Consumer: "+n--);
if(n==maxSize-1)
notifyAll();
}
}
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer(100);
}
}
Upvotes: 2
Views: 7196
Reputation: 242726
wait()
should always be used in the following way:
while(condition not met)
wait();
Otherwise some thread can wake up and continue when condition is still not met. There are two possible reasons for this situation:
notifyAll()
, you awake all waiting threads, so that some of them can be too late, when condition is false again (i.e. when limited resource is already exhausted by other threads).notify
).If you actually need to wake up only one thread, you can use notify()
instead of notifyAll()
. It eliminates the first problem, but still can't protect you from spurious wakeups, so that while
is still required.
Upvotes: 8