简体   繁体   中英

I need help I want to exit the program

**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 ()

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(); }
    }
}

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; eg

    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 (eg BlockingArrayQueue ) rather than an a bare List as your queue. And avoid doing low-level wait and notify if possible.

One of the problems with coordinating multiple producers and multiple consumers is the problem that the consumers may execute faster than the producers. Thus, detecting an empty buffer cannot always be an indication that the producers have ended production.

As long as a producer is producing this problem needs the consumers to continue consuming, while at the same time finding a way to terminate all the consumers once the producers are terminated and all the data is read from the buffer.

The following solution is provided using the Ada programming language. The solution is spread across three files.

File: prod_con_shut_down.ads

package prod_con_shut_down is
   task type Producer;
   task type Consumer;
end prod_con_shut_down;

The Ada package specification above exposes only two items, the Producer task type and the Consumer task type.

The implementation of the prod_con_shut_down package is in the second file: File: prod_con_shut_down.adb

with Ada.Numerics.Discrete_Random;
with Ada.Text_IO; use Ada.Text_IO;

package body prod_con_shut_down is

   type Buf_Idx is mod 4;
   type Buf_arr is array (Buf_Idx) of Integer;

   ------------
   -- buffer --
   ------------

   protected buffer is
      entry Write (Item : in Integer);
      entry Read (Item : out Integer);
      entry Register_Consumer;
      procedure Register_Producer;
      procedure Producer_Done;
      function Producers_Done return Boolean;
      function Is_Empty return Boolean;
   private
      Buf            : Buf_arr;
      Write_Idx      : Buf_Idx := 0;
      Read_Idx       : Buf_Idx := 0;
      Count          : Natural := 0;
      Producer_Count : Natural := 0;
   end buffer;

   protected body buffer is
      -----------
      -- Write --
      -----------

      entry Write (Item : in Integer) when Count < Buf'Length is
      begin
         Buf (Write_Idx) := Item;
         Write_Idx       := Write_Idx + 1;
         Count           := Count + 1;
      end Write;

      ----------
      -- Read --
      ----------

      entry Read (Item : out Integer) when Count > 0 is
      begin
         Item     := Buf (Read_Idx);
         Read_Idx := Read_Idx + 1;
         Count    := Count - 1;
      end Read;

      -----------------------
      -- Register_Consumer --
      -----------------------

      entry Register_Consumer when Producer_Count > 0 is
      begin
         null;
      end Register_Consumer;

      -----------------------
      -- Register_Producer --
      -----------------------

      procedure Register_Producer is
      begin
         Producer_Count := Producer_Count + 1;
      end Register_Producer;

      -------------------
      -- Producer_Done --
      -------------------

      procedure Producer_Done is
      begin
         Producer_Count := Producer_Count - 1;
      end Producer_Done;

      --------------------
      -- Producers_Done --
      --------------------

      function Producers_Done return Boolean is
      begin
         return Producer_Count = 0;
      end Producers_Done;

      --------------
      -- Is_Empty --
      --------------

      function Is_Empty return Boolean is
      begin
         return Count = 0;
      end Is_Empty;

   end buffer;

   --------------
   -- Producer --
   --------------

   task body Producer is
      subtype Nums is Integer range 1 .. 1_000;
      package Rand_Nums is new Ada.Numerics.Discrete_Random (Nums);
      use Rand_Nums;
      Seed : Generator;
      Num  : Nums;
   begin
      Reset (Seed);
      buffer.Register_Producer;
      for I in 1 .. 5 loop
         Num := Random (Seed);
         buffer.Write (Num);
         Put_Line ("Producer produced" & Num'Image);
      end loop;
      buffer.Producer_Done;
   end Producer;

   --------------
   -- Consumer --
   --------------

   task body Consumer is
      Num : Integer;
   begin
      buffer.Register_Consumer;
      loop
         select
            buffer.Read (Num);
            Put_Line ("Consumed" & Num'Image);
            delay 0.1;
         or
            delay 0.001;
         end select;
         exit when buffer.Producers_Done and buffer.Is_Empty;
      end loop;

   end Consumer;

end prod_con_shut_down;

The Register_Producer procedure increments the Producer_Count member of the Buffer protected object. The Register_Consumer entry simply forces the Consumers to wait for a producer to register before doing anything else. The Producers_Done function returns True when all producers have called Producer_Done. The loop within the Consumer exits when Producers_Done is true and Is_Empty is true.

The third file is the program entry point. Ada allows the program entry point to have any name the programmer chooses. In this example I chose "main".

File: main.adb

with prod_con_shut_down; use Prod_con_shut_down;

procedure Main is
  
   P : array (1..2) of Producer;
   C : array (1..2) of Consumer;

begin
   null;
end Main;

The main procedure creates an array of Producers containing two producers, then it creates an array of Consumers containing two Consumers. After that the main procedure simply suspends until all the producer and consumer tasks complete.

A sample execution of this program, with the producers running much slower than the consumers is:

Producer produced 157
Consumed 157
Producer produced 924
Producer produced 544
Producer produced 365
Producer produced 653
Consumed 653
Producer produced 940
Consumed 924
Producer produced 523
Producer produced 660
Consumed 544
Consumed 940
Consumed 365
Producer produced 431
Producer produced 733
Consumed 523
Consumed 660
Consumed 431
Consumed 733

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM