2011-06-17 110 views
0

我必須使用多線程編寫這個產品消費者應用程序。我編寫了下面的java代碼,但卻無法弄清楚它出錯的地方。另外我想知道我的課程設計是否合適,或者我的編碼風格是否合適。線程鎖和條件變量,生產者消費者示例

在此先感謝!

編輯

我已經修改了農產品消費代碼:但它仍然有一些問題。

import java.util.*; 
import java.lang.Thread; 

public class pc_example { 

public static void main (String [] args) { 
    Store store = new Store(10); 
    produce p = new produce(store); 
    consume c = new consume (store); 
    p.start(); 
    c.start(); 
} 

}

class Store { 
public Queue<Integer> Q; 
public int max_capacity; 

Store(int max_capacity) { 
    Q = new LinkedList<Integer>(); 
    this.max_capacity = max_capacity; 
} 

}

class produce extends Thread { 

private Store store; 
private int element; 

produce (Store store) { 
    this.store = store; 
    this.element = 0; 
} 



public void put() { 
    synchronized (store) { 
     if (store.Q.size() > store.max_capacity) { 
      try { 
       wait(); 
      } catch (InterruptedException e) {} 
     } 
     else { 
      element ++; 
      System.out.println("Producer put: " + element); 
      store.Q.add(element); 
      notify(); 
     }    
    }   
} 

}

class consume extends Thread { 
private int cons; 
private Store store; 

consume (Store store) { 
    this.store = store; 
    this.cons = 0; 
} 

public void get() { 
    synchronized (store) { 
     if (store.Q.size() == 0) { 
      try { 
       wait(); 
      } catch (InterruptedException e) {} 
     } 
     else { 
      int a = store.Q.remove(); 
      System.out.println("Consumer put: " + a); 
      cons++; 

      if (store.Q.size() < store.max_capacity) 
       notify(); 
     } 
    } 
} 

}

回答

1

對於一個完整的示例請參閱java api中針對BlockingQueue的生產者 - 消費者示例。


代碼中有幾個錯誤。首先,生產者和消費者不使用相同的隊列,例如有兩個隊列實例。其次notifywait方法也在不同的對象上運行。

讓您的例子來工作需要幾件事情:

  1. 只有一個隊列
  2. 線程隊列
  3. 的安全處理的處理通知,並等待在同一對象上

製片人代碼可以被重寫爲:

public void produce() { 
    int i = 0; 
    while (i < 100) { 
     synchronized(Q) { 
      if (Q.size() < max_capacity) { 
       Q.add(i); 
       System.out.println("Produced Item" + i); 
       i++; 
       Q.notify(); 
      } else { 
       try { 
        Q.wait(); 
       } catch (InterruptedException e) { 
        System.out.println("Exception"); 
       } 
      } 
     } 
    } 
} 
+0

好吧,我同意存在兩個不同的Q對象。 HOwever我不明白需要同步Q對象,一旦我同步方法本身? – 2011-06-18 03:01:09

+0

如果你調用'object2.notify()',它會通知一個等待該對象的線程('object2')。在你的(當前)例子中,你等待一個對象並通知另一個對象 - 它們之間沒有連接。 (我從'produce()'方法中刪除'synchronized',因爲它不是必需的。) – dacwe 2011-06-18 08:43:22

1

您正在創建Producer_Consumer的兩個實例,它們有自己的隊列,所以沒有共享。您不應該在類中實例化隊列,而應將其作爲構造函數參數提供給外部。

class Producer_Consumer extends Thread { 

private final Queue<Integer> queue; 

Producer_Consumer(int mode, Queue<Integer> queue) 
{ 
    this.queue = queue; 
} 

public static void main(String[] args) 
{ 
    Queue<Integer> queue = new LinkedQueue<Integer>(); 
    Producer_Consumer produce = new Producer_Consumer(queue, 2); 
    Producer_Consumer consume = new Producer_Consumer(queue, 1); 
    produce.start(); 
    consume.start(); 
} 
} 

可以按照建議使用來自java.util.concurrent包的阻塞隊列進行進一步的改進。對於這類任務,真的不需要使用Object的方法wait()notify()

+1

哼,因爲隊列在線程之間共享,所以在訪問之前它必須被鎖定! – dacwe 2011-06-17 07:44:41

+0

@Pavlovic您是否對Blocking Queue和java.util.concorrent包有所瞭解? – 2011-06-17 07:49:11

+0

@dacwe我同意,但如果你想教別人,最好是一步一步地做下去 – 2011-06-17 08:05:44

0

1,使用適當的類型。你的模式更像en而不是int。
2,線程之間的通道Q實際上並不共享,因爲它沒有被聲明爲靜態的。
無論如何,你會有問題,因爲鏈表不同步。
同步produce()consume()沒有區別。

0

你的對象中的每一個工作的

Queue<Integer> Q 

AA不同的實例,以使生產者把東西融入其中,但消費者從來沒有穿那一個 - 它試圖從Q得到物品,從來沒有得到任何東西放入它。

但是,一旦解決該問題,您需要確保Queue<>對象以線程安全方式處理。雖然produce()consume()方法都是同步的,但由於您要處理兩個不同的Producer_Consumer對象,因此在此級別的同步將無濟於事。他們需要以其他方式同步訪問共享資源。

+0

有兩個類的實例試圖使用共享資源執行反向任務,需要使用同步。我說的這兩個實例事實上是兩個線程正在運行。在一個實例中,產品方法在其他消費方法中運行。另外我同意我應該有一個globl隊列。另外怎麼可能在java中聲明全局變量? – 2011-06-17 07:52:44

0

我建議看看java.util.concurrent中的類(可從Java 1.5獲得)。特別是,您可以使用BlockingQueue而不是Queue。

它可以讓你產生:

try { 
    while(true) { queue.put(produce()); } 
} catch (InterruptedException ex) { ... handle ...} 

和消費:

try { 
    while(true) { consume(queue.take()); } 
} catch (InterruptedException ex) { ... handle ...} 

Otherwize,(如果這是對Java同步練習),你應該

  • 提高字段的可見性(爲什麼只有max_capacity是私人的?)
  • 完善的設計(我喜歡創造生產兩個獨立的類和消費者)
  • 確保生產者和消費者等待和SAME對象通知
  • 使生產者和消費者在同一個隊列工作
0

您的線程類中缺少運行方法。所以你的線程開始並沒有做任何事情。重命名put並獲取運行的方法並使用while循環。另外請注意,您需要調用通知並在商店(監視器)上等待。

public void run() { 

     while(true){ 
     synchronized (store) { 
      if (store.Q.size() > store.max_capacity) { 
       try { 
        store.wait(); 
       } catch (InterruptedException e) {} 
      } 
      else { 
       element ++; 
       System.out.println("Producer put: " + element); 
       store.Q.add(element); 
       store.notify(); 
      }    
     } 
    } 
    }