2011-06-17 58 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(); 
      }    
     } 
    } 
    }