生产者消费者没有给出期望的结果

Producer consumer not giving desired result

我正在从 java documentation. I implemented a famous problem Producer-consumer problem. But it is not giving result as expected. I've searched a lot about this problem at HERE, HERE, HERE, HERE, HERE 和其他一些堆栈交换和非堆栈交换站点学习线程同步,但无法解决我的问题。这是我的代码:

GetSetItem.java

public class GetSetItem {

   private volatile boolean available = false;

   private int item;

   public synchronized void set(int item) {
      while(available) {
        try {
            wait();
         } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
         }
       }

       this.item = item;
       available = true;
       notifyAll();
   }

   public synchronized int get() {
      while(!available) {
        try {
           wait();
         } catch (InterruptedException ie) {
            System.err.println("Interrupted: " + ie.getMessage());
         }
       }
       available = false;
       notifyAll();
       return item;
   }

}

Consumer.java

public class Consumer implements Runnable {

   private int number; // Just for show #1,#2 etc. For future use
   private GetSetItem consumer;

   public Consumer(GetSetItem item, int seq) {
      consumer = item;
      number = seq;
   }

   @Override
   public void run() {
      int value = -1;

      for(int i = 0; i < 10; i++) {
         value = consumer.get();
         System.out.println("Consumer #" + number + " get: " + value);
      }

   }
}

Producer.java

public class Producer implements Runnable  {

    private GetSetItem producer;

    private int number = 0;

    public Producer(GetSetItem item, int seq) {
       producer = item;
       number = seq;
    }

    @Override
    public void run() {
       for(int i = 0; i < 10; i++) {
         producer.set(i);
         System.out.println("Producer #" + number + " Put: " + i);
       }
    }

}

ProducerConsumerMain.java

public class ProducerConsumerMain {

    public static void main(String[] args) {

       GetSetItem item = new GetSetItem();

       Producer p = new Producer(item, 1);
       Consumer c = new Consumer(item, 1);

       new Thread(p).start();
       new Thread(c).start();

    }

}

输出为:

Consumer #1 get: 0
Producer #1 Put: 0
Producer #1 Put: 1
Consumer #1 get: 1
Producer #1 Put: 2
Consumer #1 get: 2
Producer #1 Put: 3
Consumer #1 get: 3
Producer #1 Put: 4
Producer #1 Put: 5
Consumer #1 get: 4
Consumer #1 get: 5
Producer #1 Put: 6
Producer #1 Put: 7
Consumer #1 get: 6
Consumer #1 get: 7
Consumer #1 get: 8
Producer #1 Put: 8
Producer #1 Put: 9
Consumer #1 get: 9

但输出应该是生产者 -> 消费者格式。这意味着消费者只有在生产者可用并生产的情况下才能消费该物品。我也试过 private boolean available = false 而不是 private volatile boolean available = false; 但没有收到预期的输出。

所以请告诉我我做错了什么,我怎样才能成功解决这个问题。

您的代码看起来不错,问题很可能是 System.out 不是线程安全的。您还需要同步您的 println() 呼叫:

@Override
public void run() {
    for (int i = 0; i < 10; i++) {
        producer.set(i);
        synchronized (System.out) {
            System.out.println("Producer #" + number + " Put: " + i);
        }
    }
}

然后,输出将类似于:

Producer #1 Put: 0
Producer #1 Put: 1
Consumer #1 get: 0
Consumer #1 get: 1
Producer #1 Put: 2
Producer #1 Put: 3
Consumer #1 get: 2
Consumer #1 get: 3
Producer #1 Put: 4
Consumer #1 get: 4
Producer #1 Put: 5
Producer #1 Put: 6
Consumer #1 get: 5
Consumer #1 get: 6
Consumer #1 get: 7 <<<<
Producer #1 Put: 7 <<<<
Producer #1 Put: 8
Consumer #1 get: 8
Consumer #1 get: 9 <<<<
Producer #1 Put: 9 <<<<

您的线程仍有可能在 get/setprintln 语句之间暂停,在这种情况下,您的消费者似乎正在消费尚未生产的东西,例如 where我在上面的输出中指出。不过,这只是一个输出问题,您的代码运行良好并且执行了它应该执行的操作。

我通过使用 get() 中的 System.out.println(...) 语句和 GetSetItem class 的 set() 方法并从中删除 System.out.println(...) 解决了这个问题对应producerconsumerclass。作为:
get() 方法 GetSetItem.java

public synchronized void set(int item, int number) {
    while(available) {
        try {
        wait();
        } catch (InterruptedException ie) {
        System.err.println("Interrupted: " + ie.getMessage());
        }
    }

    this.item = item;


    /* Putting this line here gives expected output because this   
     * statement is synchronized due to method synchronization.  
     */
        System.out.println("Producer #" + number + " Produced: " + item);            

        available = true;
        notifyAll();
}

set() 方法 of GetSetItem.java

public synchronized int get(int number) {
    while (!available) {
        try {
        wait();
        } catch (InterruptedException ie) {
        System.err.println("Interrupted: " + ie.getMessage());
        }
    }
    /*
     * Putting this line here gives expected output because this statement
     * is synchronized due to method synchronization.
     */


    System.out.println("Consumer #" + number + " Consumed: " + item);


    available = false;
    notifyAll();
    return item;
}

编辑: 输出:

Producer #1 Produced: 0
Consumer #1 Consumed: 0
Producer #1 Produced: 1
Consumer #1 Consumed: 1
Producer #1 Produced: 2
Consumer #1 Consumed: 2
Producer #1 Produced: 3
Consumer #1 Consumed: 3
Producer #1 Produced: 4
Consumer #1 Consumed: 4
Producer #1 Produced: 5
Consumer #1 Consumed: 5
Producer #1 Produced: 6
Consumer #1 Consumed: 6
Producer #1 Produced: 7
Consumer #1 Consumed: 7
Producer #1 Produced: 8
Consumer #1 Consumed: 8
Producer #1 Produced: 9
Consumer #1 Consumed: 9