繁体   English   中英

生产者消费者没有给出想要的结果

[英]Producer consumer not giving desired result

我正在从java 文档学习线程同步。 我实现了一个著名的问题生产者-消费者问题。 但它没有按预期给出结果。 我在HEREHEREHEREHEREHERE和其他一些堆栈交换和非堆栈交换站点上搜索了很多关于这个问题,但无法解决我的问题。 这是我的代码:

获取设置项.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;
   }

}

消费者.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);
      }

   }
}

生产者.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语句之间暂停,在这种情况下,它看起来好像您的消费者正在消费尚未生产的东西,就像我在上面的输出中指出的那样。 不过,这只是一个输出问题,您的代码运行良好,并完成了它应该做的事情。

我通过在GetSetItem类的get()set()方法中使用System.out.println(...)语句并从相应的producerconsumer类中删除System.out.println(...)解决了这个问题。 作为:
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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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