**I need help in this code its simple code about bounded buffer problem using multiple producers and consumers its working and there are no issues with it .... but when the producers finished the consumers still waiting and the program running forever so how can I solve this **```
//main class
import java.util.LinkedList;
import java.util.List;
public class MULTIPLE_ProducerConsumerWaitNotify {
public static void main(String args[]) {
List<Integer> sharedQueue = new LinkedList<Integer>(); //Creating shared object
Producer producer0=new Producer(sharedQueue, 0);
Consumer consumer0=new Consumer(sharedQueue);
Thread producerThread0 = new Thread(producer0, "ProducerThread0");
Thread consumerThread0 = new Thread(consumer0, "ConsumerThread0");
producerThread0.start();
consumerThread0.start();
Producer producer1=new Producer(sharedQueue, 1);
Consumer consumer1=new Consumer(sharedQueue);
Thread producerThread1 = new Thread(producer1, "ProducerThread1");
Thread consumerThread1 = new Thread(consumer1, "ConsumerThread1");
producerThread1.start();
consumerThread1.start();
}
}
//producer class
class Producer implements Runnable {
private List<Integer> sharedQueue;
private int maxSize=4; //maximum number of products which sharedQueue can hold at a time.
static int productionSize=5; //Total no of items to be produced by each producer
int producerNo;
public Producer(List<Integer> sharedQueue, int producerNo) {
this.sharedQueue = sharedQueue;
this.producerNo = producerNo;
}
@Override
public void run() {
for (int i = 1; i <= productionSize; i ) { //produce products.
try {
produce(i);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
private void produce(int i) throws InterruptedException {
synchronized (sharedQueue) {
//if sharedQuey is full wait until consumer consumes.
while (sharedQueue.size() == maxSize) {
System.out.println(Thread.currentThread().getName() ", Queue is full, producerThread is waiting for "
"consumerThread to consume, sharedQueue's size= " maxSize);
sharedQueue.wait();
}
//Bcz each producer must produce unique product
//Ex= producer0 will produce 1-5 and producer1 will produce 6-10 in random order
int producedItem = (productionSize*producerNo) i;
System.out.println(Thread.currentThread().getName() " Produced : " producedItem);
sharedQueue.add(producedItem);
Thread.sleep((long)(Math.random() * 1000));
sharedQueue.notify();
}
}
}
//consumer class
class Consumer implements Runnable {
private List<Integer> sharedQueue;
public Consumer(List<Integer> sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
while (true) {
try {
consume();
Thread.sleep(100);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
private void consume() throws InterruptedException {
synchronized (sharedQueue) {
//if sharedQuey is empty wait until producer produces.
while (sharedQueue.size() == 0) {
System.out.println(Thread.currentThread().getName() ", Queue is empty, consumerThread is waiting for "
"producerThread to produce, sharedQueue's size= 0");
sharedQueue.wait();
}
Thread.sleep((long)(Math.random() * 2000));
System.out.println(Thread.currentThread().getName() ", CONSUMED : " sharedQueue.remove(0));
sharedQueue.notify();
}
}
}
i tried to make a shared counter when it's done the code exit ()
CodePudding user response:
It's because the consumer's desire is unlimited. That's the main problem in the world. ^^
In the class Producer, there is the limitation for the production.
static int productionSize=5; //Total no of items to be produced by each producer
and the loop is finite.
for (int i = 1; i <= productionSize; i ) { //produce products.
But in the class Consumer, there is no such kind of limitation.
And the loop is infinite, so the program cannot be finished.
while (true)
Maybe we can add variables, wants and gets, in the Consumer class
to limit the run loop as below.
static int wants = 5;
int gets = 0;
@Override
public void run() {
gets = 0;
while (gets < wants) {
try {
consume();
gets ;
Thread.sleep(100);
} catch (InterruptedException e) { e.printStackTrace(); }
}
}
CodePudding user response:
There are a number of approaches to solving this problem ... in general.
Using Counters
If you know beforehand how many items will need to be consumed then the consumers can maintain a (shared) counter and stop themselves when the counter hits the limit. The problems with this are:
If may be hard or impossible to predict the number of items that will be produced.
Given the following (hypothetical) consumer implementation:
while (atomicCounter.get() < limit) { product = queue.take(); // this blocks until something // is available to be consumed. atomicCounter.increment(); process(product); }
... there is a the problem of getting all of the consumers to notice that the limit has been reached. So you need to use
poll
and a retry mechanism ... which means busy waiting; e.g.while (atomicCounter.get() < limit) { product = queue.poll(timeout, unit); if (product != null) { atomicCounter.increment(); process(product); } }
The astute reader will notice that consumers don't terminate immediately. They need to wait for the
poll
timeout to expire before they will notice that the limit has been reached.
Using a Poison Pill.
If the producers (or something else) knows when they have produced the last "product" and added it to the queue, they add a poison pill to object to the queue. When a consumer gets this poison pill, it "consumes" it and dies. In practice it might look like this:
while (true) {
product = queue.take();
if (product == POISON_PILL) {
break;
}
process(product);
}
It is slightly more complicated when there are multiple consumers:
- You could provide one pill for each consumer, or enqueue the same pill multiple times.
- You could have the consumer re-enqueue the poison pill as its last action before dying.
Other approaches
There should be a way to do this using Thread.interrupt
but it will be complicated. There needs to be something "in charge" that can figure out when to interrupt the consumer threads ... and they need to respond correctly.
It might be possible to do this using daemon thread semantics. However, if you simply mark the consumer threads as daemon, the JVM will shut down as soon as the producers terminate. That is too soon.
In your example, I would use the poison pill approach. But there are other things that you should fix first. For example, use a Queue
class (e.g. BlockingArrayQueue
) rather than an a bare List
as your queue. And avoid doing low-level wait
and notify
if possible.