2013-06-21 25 views
4

我爲生產者/消費者模式實現了一個緩衝區,但是,似乎消費者從未獲得鎖,所以發生飢餓。我不能確定爲什麼會發生這種情況,因爲put()和take()似乎正確地釋放了鎖...在Java中爲生產者/消費者模式創建一個同步緩衝區

我知道有BlockingQueue和其他很好的實現,但我想用wait()並通知()作爲練習。

public class ProducerConsumerRaw { 

    public static void main(String[] args) { 
     IntBuffer buffer = new IntBuffer(8); 

     ConsumerRaw consumer = new ConsumerRaw(buffer); 
     ProducerRaw producer = new ProducerRaw(buffer); 

     Thread t1 = new Thread(consumer); 
     Thread t2 = new Thread(producer); 

     t1.start(); 
     t2.start(); 

    } 
} 

class ConsumerRaw implements Runnable{ 
    private final IntBuffer buffer; 

    public ConsumerRaw(IntBuffer b){ 
     buffer = b; 
    } 

    public void run() { 
     while(!buffer.isEmpty()) { 
      int i = buffer.take(); 
      System.out.println("Consumer reads "+i); // this print may not be in the order 
     } 
    } 
} 


class ProducerRaw implements Runnable{ 
    private final IntBuffer buffer; 

    ProducerRaw(IntBuffer b) { 
     this.buffer = b; 
    } 

    public void run(){ 
     for (int i = 0; i < 20; i++) { 
      int n = (int) (Math.random()*100); 
      buffer.put(n); 
      System.out.println("Producer puts "+n); 
     } 
    } 
} 


class IntBuffer{ 

    private final int[] storage; 
    private volatile int end; 
    private volatile int start; 

    public IntBuffer(int size) { 
     this.storage = new int[size]; 
     end = 0; 
     start = 0; 
    } 


    public void put(int n) { // puts add the END 
     synchronized(storage) { 
      boolean full = (start == (end+storage.length+1)%storage.length); 
      while(full){ // queue is full 
       try { 
        storage.notifyAll(); 
        storage.wait(); 

       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      this.storage[end] = n; 
      end = incrementMod(end); 
      storage.notifyAll(); 
     } 
    } 


    public int take(){ 

     synchronized(storage) { 
      while (end == start) { // empty queue 
       try { 
        storage.notifyAll(); // notify waiting producers 
        storage.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      int index = start; 
      start = incrementMod(start); 
      storage.notifyAll(); // notify waiting producers 
      return this.storage[index]; 

     } 
    } 

    private int incrementMod(int index) { 
     synchronized (storage) { 
      if (index == storage.length-1) return 0; 
      else return index+1; 
     } 
    } 

    public boolean isEmpty(){ 
     synchronized (storage) { 
      return (start == end); 
     } 
    } 

} 

回答

6

這至少是一個問題,在您的put方法:

boolean full = (start == (end+storage.length+1)%storage.length);   
while(full){ // queue is full 
    // Code that doesn't change full 
} 

如果full曾經被初始化爲true,你怎麼能指望循環結束?

其他問題是這樣的循環,在消費者:

while(!buffer.isEmpty()) { 
    int i = buffer.take(); 
    System.out.println("Consumer reads "+i); 
} 

你假設製片人從來沒有讓緩衝區得到空 - 如果消費者生產者開始之前,它會立即停止。

取而代之,您需要某種方式告訴您已停止生成的緩衝區。消費者應該繼續服用,直到隊列爲空將不會再收到任何數據。

+0

哇,謝謝你指出了!它現在可以工作,但是我很欣賞對如何改進代碼的任何評論 – ksiomelo

+4

@ksiomelo:那麼顯而易見的改進是使用java.util.concurrent中的專門爲此設計的類:) –

相關問題