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

时间:2015-02-24 11:09:03

标签: java multithreading synchronization producer-consumer

我从java documentation学习线程同步。我实施了一个着名的问题生产者 - 消费者问题。但它没有按预期给出结果。我在HEREHEREHEREHEREHERE以及其他一些堆栈交换中搜索了很多关于此问题的信息。堆栈交换站点,但无法解决我的问题。这是我的代码:

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

但输出应该在生产者中 - &gt;消费者格式。这意味着消费者只有在生产者可用和生产的情况下才能消费。我还尝试了private boolean available = false而不是private volatile boolean available = false;,但没有收到预期的输出。

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

2 个答案:

答案 0 :(得分:1)

您的代码似乎很好,问题很可能是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语句之间暂停,在这种情况下,看起来好像您的消费者正在消费尚未生成的内容,例如我指示的位置在上面的输出中。但这只是一个输出问题,你的代码运行正常并完成它应该做的事情。

答案 1 :(得分:1)

我在System.out.println(...)类的get()set()方法中使用GetSetItem语句,并从相应的System.out.println(...)中移除producer,从而解决了问题和consumer课程。正如:
GetSetItem.java的 get()方法

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();
}
GetSetItem.java的

set()方法

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