我的农产品消费者挂起

Posted

技术标签:

【中文标题】我的农产品消费者挂起【英文标题】:My Produce Consumer Hangs 【发布时间】:2011-03-05 07:36:21 【问题描述】:

请复制下面的程序并尝试在您的 IDE 中运行。这是一个简单的 Producer Consumer 实现 - 当我使用一个 Producer 和一个 Consumer 线程时它运行良好,但在每个使用 2 个时失败。请告诉我这个程序挂起的原因或者还有什么问题。

import java.util.LinkedList;
import java.util.Queue;

public class PCQueue 

 private volatile Queue<Product> productQueue = new LinkedList<Product>();

 public static void main(String[] args) 
  PCQueue pc = new PCQueue();

  Producer producer = new Producer(pc.productQueue);
  Consumer consumer = new Consumer(pc.productQueue);

  new Thread(producer, "Producer Thread 1").start();
  new Thread(consumer, "Consumer Thread 1").start();

  new Thread(producer, "Producer Thread 2").start();
  new Thread(consumer, "Consumer Thread 2").start();
 



class Producer implements Runnable 

 private Queue<Product> queue = null;

 private static volatile int refSerialNumber = 0;

 public Producer(Queue<Product> queue) 
  this.queue = queue;
 

 @Override
 public void run() 

  while (true) 
   synchronized (queue) 
    while (queue.peek() != null) 
     try 
      queue.wait();
      catch (InterruptedException e) 
      // TODO Auto-generated catch block
      e.printStackTrace();
     
    
    queue.add(new Product(++refSerialNumber));
    System.out.println("Produced by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + refSerialNumber);

    queue.notify();
   
  

 


class Consumer implements Runnable 

 private Queue<Product> queue = null;

 public Consumer(Queue<Product> queue) 
  this.queue = queue;
 

 @Override
 public void run() 
  while (true) 
   synchronized (queue) 
    while (queue.peek() == null) 
     try 
      queue.wait();
      catch (InterruptedException e) 
      // TODO Auto-generated catch block
      e.printStackTrace();
     
    

    Product product = queue.remove();
    System.out.println("Consumed by: "
      + Thread.currentThread().getName() + " Serial Number: "
      + product.getSerialNumber());

    queue.notify();

   
  

 



class Product 
 private int serialNumber;

 public Product(int serialNumber) 
  this.serialNumber = serialNumber;
 

 public int getSerialNumber() 
  return serialNumber;
 

【问题讨论】:

【参考方案1】:

问题是您使用 queue.notify() 只会唤醒等待队列的单个线程。想象一下 Producer 1 调用 notify() 并唤醒 Producer 2。Producer 2 看到队列中有东西,所以他没有生产任何东西,只是回到 wait() 调用。现在你的生产者和消费者都在等待通知,没有人在工作来通知任何人。

要解决代码中的问题,请使用 queue.notifyAll() 唤醒在 wait() 中阻塞的每个线程。这将允许您的消费者运行。

请注意,您的实现将队列限制为最多包含一个项目。所以你不会从第二组生产者和消费者中看到任何好处。为了更好的实现,我建议您查看BlockingQueue 并使用可以有界的实现,例如ArrayBlockingQueue。无需同步和使用等待/通知,只需使用BlockingQueue.offer() 和BlockingQueue.take()。

【讨论】:

哎呀.. 傻我.. 终于我可以使用 notifyAll().. 非常感谢!!【参考方案2】:

使用 queue.notifyAll() 代替 queue.notify()

【讨论】:

以上是关于我的农产品消费者挂起的主要内容,如果未能解决你的问题,请参考以下文章

RabbitMQ 挂起队列消费

我正在尝试获取我的产品消费者当前状态

Java多线程程序挂起

JmsListener 没有收到来自 Activemq 的消息

农产品追溯系统开发 一物一码连接消费者

生产者-消费者模式